<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mohamed Ashiq Sultan</title>
    <description>The latest articles on DEV Community by Mohamed Ashiq Sultan (@ashiqsultan).</description>
    <link>https://dev.to/ashiqsultan</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F248223%2Fee4aea94-3f48-4f70-97d2-f36cc4e2e26f.jpeg</url>
      <title>DEV Community: Mohamed Ashiq Sultan</title>
      <link>https://dev.to/ashiqsultan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ashiqsultan"/>
    <language>en</language>
    <item>
      <title>Built my first TUI as a web dev and the experience was awesome</title>
      <dc:creator>Mohamed Ashiq Sultan</dc:creator>
      <pubDate>Sun, 15 Feb 2026 07:27:22 +0000</pubDate>
      <link>https://dev.to/ashiqsultan/built-my-first-tui-as-a-web-dev-and-the-experiecnce-was-awesome-1i8n</link>
      <guid>https://dev.to/ashiqsultan/built-my-first-tui-as-a-web-dev-and-the-experiecnce-was-awesome-1i8n</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/github-2026-01-21"&gt;GitHub Copilot CLI Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;I built a Terminal UI to ralph loop Github Copilot to automate vibe codeing tasks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/LliYBcpng15xUqJfiK/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/LliYBcpng15xUqJfiK/giphy.gif" width="480" height="256"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I previously built this as a &lt;a href="https://dev.to/ashiqsultan/copilot-ralph-built-a-desktop-ui-for-github-copilot-59h7"&gt;Desktop app&lt;/a&gt; but realized I myself spend most time in terminal so why not build this as a TUI as this be learning experience for me on TUIs&lt;/p&gt;

&lt;p&gt;Now since this is available as an NPM package you can try this out easily with &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;npm i -g copilot-ralp&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;cd to your project and run &lt;code&gt;copilot-ralp&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/ashiqsultan/copilot-ralph-tui" rel="noopener noreferrer"&gt;Github&lt;/a&gt;
&lt;/h3&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.npmjs.com/package/copilot-ralph" rel="noopener noreferrer"&gt;NPM&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/JlGQnzl6khY"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  My Experience with GitHub Copilot CLI
&lt;/h2&gt;

&lt;p&gt;I have used Copilot in VSCode mostly and this is my first time using AI tool in a CLI. I especially liked the Resume feature and the premium request usage metrics we get at the end.&lt;/p&gt;

&lt;h2&gt;
  
  
  Experience building TUI as a web developer
&lt;/h2&gt;

&lt;p&gt;I have been developing web application for almost a decade and this is my first time trying a TUI.&lt;/p&gt;

&lt;p&gt;When thinking which libraries to use, I was initially exploring non JS libraries as react was the last thing I want to write on a TUI but dobled down on &lt;a href="https://github.com/vadimdemedes/ink" rel="noopener noreferrer"&gt;React Ink&lt;/a&gt; anyways 😅 as I dont like to vibe code stuff I'm not so familiar with.&lt;/p&gt;

&lt;p&gt;Thanks to copilot that setup was a breeze. I was able to reuse some logic from my electron code also since its React, the jsx way to layout and handle state in the CLI was understandable at first glance.&lt;/p&gt;

&lt;p&gt;So I realized in TUI its not mouse clicks anymore and its just keyboard-driven. I had to unlearn the usual Web UI brain of “&lt;em&gt;yeah, the user will just click that&lt;/em&gt;” and shft to “&lt;em&gt;how would the user know this exists&lt;/em&gt;” mindset. Surprisingly copilot added a little bar at the bottom like in older Turbo C and nano editor this was somthing I wouldnt have comeup myself.&lt;/p&gt;

&lt;p&gt;One thing for sure AIs are getting better at coding and its high time  that we utilize them to learn and build something new.&lt;/p&gt;

&lt;p&gt;If you made it this far, feel free to drop a ❤️ on the post. Thanks.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>githubchallenge</category>
      <category>ai</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I Built a Desktop Client for Copilot to automate vibe coding tasks while I sleep.</title>
      <dc:creator>Mohamed Ashiq Sultan</dc:creator>
      <pubDate>Tue, 10 Feb 2026 12:45:30 +0000</pubDate>
      <link>https://dev.to/ashiqsultan/copilot-ralph-built-a-desktop-ui-for-github-copilot-59h7</link>
      <guid>https://dev.to/ashiqsultan/copilot-ralph-built-a-desktop-ui-for-github-copilot-59h7</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/github-2026-01-21"&gt;GitHub Copilot CLI Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;I built a desktop app for Copilot to work on taks in a Ralph loop mode. The app has a plan mode and also creates git commits for each task.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/lUq5LJxloxbLVzxQQz/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img width="100%" src="https://i.giphy.com/media/lUq5LJxloxbLVzxQQz/giphy.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/ashiqsultan/copilot-ralph" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;
&lt;/h3&gt;

&lt;h3&gt;
  
  
  YouTube Demo
&lt;/h3&gt;

&lt;p&gt;

  &lt;iframe src="https://www.youtube.com/embed/U796vzV5oXc"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;

&lt;h3&gt;
  
  
  Inspiration
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://ghuntley.com/loop/" rel="noopener noreferrer"&gt;Original post on Ralph loop&lt;/a&gt;. This is the post that triggered the Ralph way to use claude code. And I thought of building an UI for this for copilot because, TBH, Copilot is the chepest pricing I could find right now for AI assisted coding. &lt;/p&gt;

&lt;p&gt;My app doesn’t strictly follow the OP, because I’ve moved some responsibilities out of the AI layer and into the orchestration layer. The system now handles the following tasks:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F83otwoyqnlw2q2uzqkiu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F83otwoyqnlw2q2uzqkiu.png" alt="Architecture of copilot ralph"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Linear selection of requirements&lt;/li&gt;
&lt;li&gt;process.txt updates after each task&lt;/li&gt;
&lt;li&gt;Creating Git commits&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I made this way so the system is predictable and to reduce ambiguity of relying on AI&lt;/p&gt;

&lt;h2&gt;
  
  
  My Experience with GitHub Copilot CLI
&lt;/h2&gt;

&lt;p&gt;This is my first experice with AI in CLI (yes I dont have Claude code), before this I have used copilot only inside VSCode but using it in a CLI feels like more control. I liked how we can mention files with &lt;code&gt;@&lt;/code&gt; (which I also included in my app btw). I also loved the &lt;code&gt;--yolo&lt;/code&gt; flag and I was mostly starting my sessions with yolo mode. Almost forgot to mention the &lt;code&gt;--resume&lt;/code&gt; session was a saver and the information on how much premium request info at end of session was really helpful.&lt;/p&gt;

&lt;h3&gt;
  
  
  Choosing models
&lt;/h3&gt;

&lt;p&gt;I must say this, choosing models in copilot felt more like a survival game. As I'm in a free tier I dont want to lose all my premium requests, since my app in itself is an UI for copilot, so testing the app also means additional calls so I followed this strategy. Sonnet 4.5 for normal tasks and Opus only when required so I dont use x3 the limit. &lt;/p&gt;

&lt;p&gt;This is my typical flow&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start in yolo mode&lt;/li&gt;
&lt;li&gt;Select models based on requirement.&lt;/li&gt;
&lt;li&gt;Choose the files I think the AI should know for the task&lt;/li&gt;
&lt;li&gt;First the Plan mode&lt;/li&gt;
&lt;li&gt;Then Execute mode&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Thanks for reading
&lt;/h3&gt;

&lt;p&gt;A like on the post ❤️ would be great.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>githubchallenge</category>
      <category>cli</category>
      <category>githubcopilot</category>
    </item>
    <item>
      <title>Co-Researcher | A Medical Research tool | Multi-Agent and Real-time data</title>
      <dc:creator>Mohamed Ashiq Sultan</dc:creator>
      <pubDate>Sat, 30 Aug 2025 05:39:24 +0000</pubDate>
      <link>https://dev.to/ashiqsultan/co-researcher-accelerating-healthcare-research-with-multi-agent-ai-hjo</link>
      <guid>https://dev.to/ashiqsultan/co-researcher-accelerating-healthcare-research-with-multi-agent-ai-hjo</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/brightdata-n8n-2025-08-13"&gt;AI Agents Challenge powered by n8n and Bright Data&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;I built a Co-Research app to help scientists in healthcare and medicine get their work done faster in drug discovery. It’s uses by multiple n8n AI Agent nodes each having brightdata as their tool to retrive real-time data from internet&lt;/p&gt;

&lt;p&gt;Each agent takes care of a specific job, like pulling in &lt;strong&gt;Clinical Trial data, checking literatures, analysis of safety concerns&lt;/strong&gt; and then a final agent ties it all together into a neat summary with insights.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/_AznZqB90Aw"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Main Workflow&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsswwrq4f5yaibwp79mx5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsswwrq4f5yaibwp79mx5.png" alt="Main workflow doing research"&gt;&lt;/a&gt;&lt;br&gt;
Sub Workflow&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4qs4qurorobncdpt7mv8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4qs4qurorobncdpt7mv8.png" alt="Sub workflow bright data doing google ai search"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Live App&lt;/strong&gt; You can try the app in the below link.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://co-researcher.vercel.app" rel="noopener noreferrer"&gt;https://co-researcher.vercel.app&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  n8n Workflow
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/ashiqsultan/co-researcher/blob/main/n8n/AI-Co-Researcher-multi-agent.json" rel="noopener noreferrer"&gt;Main Workflow JSON&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/ashiqsultan/co-researcher/blob/main/n8n/Agent-brightdata-google-ai-search.json" rel="noopener noreferrer"&gt;Sub-Workflow (BrightData) JSON&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Technical Implementation
&lt;/h2&gt;

&lt;p&gt;I have created two workflows.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Main Workflow&lt;/strong&gt;: &lt;u&gt;This is where the actual research workflow happens&lt;/u&gt;. It uses multiple AI agents, with each agent handling a specific part of the research process.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Sub Workflow&lt;/strong&gt;: To search the internet using BrightData &lt;u&gt;Think of this like a resuable helper function&lt;/u&gt;. It handles web searching tasks and is &lt;u&gt;designed to work with any existing or new workflows&lt;/u&gt;. In this project, three different agents use this same sub workflow as their search tool.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;LLM Model: Well, I used Gemini Flash due to their free tier. &lt;br&gt;
Memory: I used simple memory provided by n8n&lt;br&gt;
Tools: Well, the BrightData search&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This is simply the tech stack&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Next.js: Web app&lt;/li&gt;
&lt;li&gt;n8n: Research Automation&lt;/li&gt;
&lt;li&gt;BrightData: For Searching Web&lt;/li&gt;
&lt;li&gt;AirTable: Storage&lt;/li&gt;
&lt;li&gt;Gemini: LLM &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Bright Data Verified Node
&lt;/h3&gt;

&lt;p&gt;I have used couple of bright data nodes&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Webscrapper Node with Google AI search&lt;/li&gt;
&lt;li&gt;Monitor Snapshot&lt;/li&gt;
&lt;li&gt;Download Snapshot&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Journey
&lt;/h2&gt;

&lt;p&gt;This project is an inspiration from &lt;a href="https://www.james-zou.com" rel="noopener noreferrer"&gt;James Zou&lt;/a&gt; talk on &lt;a href="https://www.youtube.com/watch?v=Yz-r7KGXbyM&amp;amp;t=929s" rel="noopener noreferrer"&gt;Virtual Lab of AI Scientists&lt;/a&gt;. Since this is just a hackathon project, I didn't capture his complete version, rather adapted the core ideas he outlined so credits to him.&lt;/p&gt;

&lt;p&gt;Okay now about my actual journey&lt;/p&gt;

&lt;p&gt;I'm completely new to both n8n and brightdata so had to watch some YouTube videos to get an overall understanding. Also as person who likes to avoid tooling and loves to code everything, this entire concept seemed too good to be true. What I personally liked is the easy integration with the various platforms with just API keys and also the orchestration of AI Agent tool, this is super cool coz If I had to code this I would easily sit at least a week on this.&lt;/p&gt;

&lt;p&gt;I started experimenting with BrightData on n8n, and initially tried using it directly as a tool in an agent node. But that didn't really work for me cox the results would get stored in a BrightData snapshot, which made it pretty tricky to orchestrate the whole process properly.&lt;/p&gt;

&lt;p&gt;So I had this idea to create a separate workflow instead and call that as a tool. Turns out this approach worked really well for me, What I ended up with was &lt;u&gt;this reusable web searching workflow that I can basically plug in anywhere I need it&lt;/u&gt; I pretty much liked this neat solution.&lt;/p&gt;

&lt;p&gt;Now all I needed is a place to store the records, I wanted to keep it simple and went with Airtable. Finally I created a Next.js app to make it accessible and view the results.&lt;/p&gt;

&lt;p&gt;You can find the code along with n8n workflow jsons in the below GitHub repo.&lt;br&gt;
&lt;a href="https://github.com/ashiqsultan/co-researcher/tree/main" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you have read it till here, a like would be great, thank you.&lt;/p&gt;

&lt;p&gt;...&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>n8nbrightdatachallenge</category>
      <category>ai</category>
      <category>webdev</category>
    </item>
    <item>
      <title>InboxMemory AI - RAG your Emails - Postmark</title>
      <dc:creator>Mohamed Ashiq Sultan</dc:creator>
      <pubDate>Wed, 28 May 2025 18:26:18 +0000</pubDate>
      <link>https://dev.to/ashiqsultan/inboxmemory-ai-rag-your-emails-postmark-1l63</link>
      <guid>https://dev.to/ashiqsultan/inboxmemory-ai-rag-your-emails-postmark-1l63</guid>
      <description>&lt;p&gt;This is a submission for the &lt;a href="https://dev.to/challenges/postmark"&gt;Postmark Challenge: Inbox Innovators&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;I have build a tool "InboxMemory AI". In short its think of it as ChatGPT for your emails. You can send emails to make it into searchable knowledge base and ask questions via email or from the app in natural language. Basically RAG from emails&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Video Walthrough
&lt;/h3&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/XntMQ-oCOQ4"&gt;
  &lt;/iframe&gt;
&lt;br&gt;
screenshots&lt;/p&gt;
&lt;h3&gt;
  
  
  QA via Email
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F59xt1acfavll1ejt5o55.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F59xt1acfavll1ejt5o55.PNG" alt="QA via Emails"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  QA via App
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F20wvmnpywj2ihumnhl2e.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F20wvmnpywj2ihumnhl2e.PNG" alt="QA via App"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Getting Started
&lt;/h3&gt;

&lt;p&gt;Just send "Hi [your name]" to the email &lt;strong&gt;&lt;code&gt;ai@kbhelper.com&lt;/code&gt;&lt;/strong&gt;. The AI picks up your name, creates your account, and you're ready to go ⚡&lt;/p&gt;
&lt;h3&gt;
  
  
  Behind the Scenes
&lt;/h3&gt;

&lt;p&gt;When you forward an email, we break it into chunks and store it in our vector database. If you send a question, our AI searches through everything you've saved and gives you an actual answer. You can also hop into the web app to browse your saved emails or ask questions with a proper interface.&lt;/p&gt;
&lt;h2&gt;
  
  
  Code Repository
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;GitHub Link&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/ashiqsultan" rel="noopener noreferrer"&gt;
        ashiqsultan
      &lt;/a&gt; / &lt;a href="https://github.com/ashiqsultan/inbox_memory_ai" rel="noopener noreferrer"&gt;
        inbox_memory_ai
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Inbox Memory AI build for Postmark hackathon | Using AI via email
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;InboxMemory AI&lt;/h1&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;📁 For detailed setup and development instructions, please check the respective READMEs inside the &lt;a href="https://github.com/ashiqsultan/inbox_memory_ai/./backend/" rel="noopener noreferrer"&gt;&lt;code&gt;backend/&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://github.com/ashiqsultan/inbox_memory_ai/./frontend/" rel="noopener noreferrer"&gt;&lt;code&gt;frontend/&lt;/code&gt;&lt;/a&gt; folders.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Postmark Hackathon Project&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;This project was built for the &lt;strong&gt;Postmark Challenge: Inbox Innovators&lt;/strong&gt; hackathon.&lt;/p&gt;
&lt;p&gt;🔗 &lt;strong&gt;Blog Post&lt;/strong&gt;: &lt;a href="https://dev.to/ashiqsultan/inboxmemory-ai-rag-your-emails-postmark-1l63" rel="nofollow"&gt;Read more about this project&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What is InboxMemory AI?&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=XntMQ-oCOQ4" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1ce464f445eada0f091988eaaac8a17240a83e5bae694fdf1f502869a02d33ad/68747470733a2f2f696d672e796f75747562652e636f6d2f76692f586e744d512d6f434f51342f302e6a7067" alt="InboxMemory AI Demo"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;InboxMemory AI is like &lt;strong&gt;ChatGPT for your emails&lt;/strong&gt;. It's an intelligent email assistant that transforms your inbox into a searchable knowledge base using RAG (Retrieval Augmented Generation) technology.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Key Features&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;📧 Email-to-Knowledge&lt;/strong&gt;: Forward emails to create a searchable knowledge base&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🤖 Natural Language Q&amp;amp;A&lt;/strong&gt;: Ask questions about your emails in plain English&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;✉️ Email Interface&lt;/strong&gt;: Query via email or through the web app&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🔍 Smart Search&lt;/strong&gt;: AI-powered semantic search through your email content&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;⚡ Quick Setup&lt;/strong&gt;: Just send "Hi [your name]" to &lt;code&gt;ai@kbhelper.com&lt;/code&gt; to get started&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;How It Works&lt;/h3&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Store&lt;/strong&gt;: Forward emails to build your knowledge…&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/ashiqsultan/inbox_memory_ai" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Techstack
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;FastAPI for the backend&lt;/li&gt;
&lt;li&gt;PostgreSQL for email storage&lt;/li&gt;
&lt;li&gt;LanceDB as our vector database&lt;/li&gt;
&lt;li&gt;Redis for OTPs and rate limiting&lt;/li&gt;
&lt;li&gt;React for the frontend&lt;/li&gt;
&lt;li&gt;Gemini handling the AI magic and embeddings&lt;/li&gt;
&lt;li&gt;Docker for deploymnet&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Along with the RAG system I ahve also build Auth system with email OTP because why not? since Postmark an email service anyways why not lets try that out. Gemini provides generous free tire which allowed me to use them.   Wrote smaller AI Agent like files with specific system instructions for each task. &lt;/p&gt;

&lt;h3&gt;
  
  
  Some challenges I faced
&lt;/h3&gt;

&lt;p&gt;I initially used Ngrok when testing in local but suprised to find no ngrok like services was mentioned in their docs. It will be a pain to initially debug without them&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffswwryhtienoomjj1q1a.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffswwryhtienoomjj1q1a.PNG" alt="Storing Process"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqgnqn82ummfbsacddq4r.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqgnqn82ummfbsacddq4r.PNG" alt="Retrival and QA Process"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Please try it
&lt;/h3&gt;

&lt;p&gt;Please try it out as of writing this I have 50 more free emails from Postmark gota use them all. If this sounds useful to you, an upvote would be great. Thanks.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>postmarkchallenge</category>
      <category>ai</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Debounce and Throttle in JS. Visualize and Understand</title>
      <dc:creator>Mohamed Ashiq Sultan</dc:creator>
      <pubDate>Fri, 25 Oct 2024 12:25:36 +0000</pubDate>
      <link>https://dev.to/ashiqsultan/never-forget-debounce-and-throttle-again-visualise-them-codepen-included-4bi6</link>
      <guid>https://dev.to/ashiqsultan/never-forget-debounce-and-throttle-again-visualise-them-codepen-included-4bi6</guid>
      <description>&lt;p&gt;This is not just another article trying to explain how Debounce or Throttling works at code level rather this is an illustration to remember and visualise the concept so that you can practically apply them at your work.&lt;/p&gt;

&lt;p&gt;Personally, I often find myself forgetting the concepts of debouncing and throttling, so when someone asks me to explain them—or if a question pops up in an interview—I just blink 😑. To avoid that, I made a simple page to help refresh my memory. If you don't want to feel like an imposter follow along 😉.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In the below codepen I have set the delay to 2 seconds for both debounce and throttle. Try clicking on random food items and give a pause.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/ashiqsultan/embed/YzmEbYB?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Index
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The Restaurant Analogy&lt;/li&gt;
&lt;li&gt;Explanation

&lt;ul&gt;
&lt;li&gt;Why Debounce or Throttle anyway ?&lt;/li&gt;
&lt;li&gt;JS Event Handler&lt;/li&gt;
&lt;li&gt;Whats wrong ?&lt;/li&gt;
&lt;li&gt;Debounce&lt;/li&gt;
&lt;li&gt;Throttle&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://ashiqsultan.github.io/debounce-throttle/" rel="noopener noreferrer"&gt;Link to page&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;a href="https://ashiqsultan.github.io/debounce-throttle/" rel="noopener noreferrer"&gt;
      ashiqsultan.github.io
    &lt;/a&gt;
&lt;/div&gt;
&lt;br&gt;
&lt;a href="https://github.com/ashiqsultan/debounce-throttle" rel="noopener noreferrer"&gt;GitHub Link&lt;/a&gt;
&lt;h1&gt;
  
  
  Restaurant Analogy
&lt;/h1&gt;

&lt;p&gt;Imagine you're at a restaurant and want to order some food, so you pick the menu from the table and you just start to read all the items. (In the webpage I shared, clicking different food items will be equivalent to reading the menu item)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The analogy here&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📖 Reading food item = 👇 Button Click&lt;/li&gt;
&lt;li&gt;👨‍🍳 Waiter going to kitchen = 🌐 API call &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;And imagine there are three different types of waiters at the restaurant who could serve you:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;💁‍♂️ Normal Waiter&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Takes note every single time you mention an item&lt;/li&gt;
&lt;li&gt;Runs to the kitchen for each individual item&lt;/li&gt;
&lt;li&gt;Like JS handling every single event immediately&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;🤵 Debounced Waiter&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When you start reading the menu he will be waiting for you to pause for atleast 2 seconds before taking the order.&lt;/li&gt;
&lt;li&gt;Like waiting for a user to finish typing before making an API call&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;👨‍🍳 Throttled Waiter&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Takes orders only once every 2 seconds&lt;/li&gt;
&lt;li&gt;If you mention multiple items within those 2 seconds, they'll all go in the same order&lt;/li&gt;
&lt;li&gt;Like limiting API calls to once every X seconds, regardless of user activity&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: The main difference is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Debouncing: Waits for activity (button click) to STOP for a specified time to trigger&lt;/li&gt;
&lt;li&gt;Throttling: Triggers at REGULAR intervals, regardless of when an activity is stopped&lt;/li&gt;
&lt;li&gt;Also 2 sec is just something I used as example it can be any timeperiod&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h1&gt;
  
  
  Explanation
&lt;/h1&gt;
&lt;h2&gt;
  
  
  Why Debounce or Throttle anyway?
&lt;/h2&gt;

&lt;p&gt;Before understanding debounce or throttle we need to know why are they even used in the first place. To know that lets understand behaviour of JS event handlers&lt;/p&gt;
&lt;h2&gt;
  
  
  Event Handlers in JS
&lt;/h2&gt;

&lt;p&gt;In JS, event handlers are just functions that execute when specific events (like clicks, typing, or scrolling) occur. &lt;strong&gt;By default, these handlers will fire every single time the event happens&lt;/strong&gt; - every keystroke, every click, or scroll movement.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Basic event handler
button.addEventListener('click', function() {
    console.log('Button clicked!');
});

// Basic keystroke handler
input.addEventListener('keyup', function() {
    console.log('Key pressed!');
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Whats wrong?
&lt;/h2&gt;

&lt;p&gt;Say for example you have a button that would make an API call&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function makeApiCall() {
  console.log("API call made");
}

button.addEventListener('click', () =&amp;gt; {
  makeApiCall();
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above function will execute the &lt;code&gt;makeApiCall()&lt;/code&gt; on each button click (i.e) &lt;strong&gt;if you manage to press it 10 times within 1 sec, guess what you have made 10 api calls in 1 sec.&lt;/strong&gt; This is the default behaviour.&lt;/p&gt;

&lt;p&gt;But firing an API call every single time for an event can be inefficient and most times this is not what you are looking for. This is where throttling and debouncing come in to picture.&lt;/p&gt;

&lt;p&gt;If you want to take away a definition from this article may be this is the one. &lt;strong&gt;Throttling and debouncing are two most common ways to control an Event Listener’s response rate.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Debouncing
&lt;/h2&gt;

&lt;p&gt;I’m not going to explain the code for debouncing as this can just be imported from lodash, rather we will see where you can actually use it.&lt;/p&gt;

&lt;p&gt;Use Debouncing when you want to make the api call only if the user has stopped typing for a certain amount of time or stopped clicking for a certain amount of time.&lt;/p&gt;

&lt;p&gt;In our example if the user keeps clicking on the button even for 5 min straight, the api call will be made only once.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So two things are happening here:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User needs to stop clicking.&lt;/li&gt;
&lt;li&gt;Stop clicking means atleast for 2 seconds there should be no clicking on the button.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Throttle
&lt;/h2&gt;

&lt;p&gt;Throttle is like an interval. Use this when you dont want to wait till the user stops rather make an api call on every interval say 2 seconds&lt;/p&gt;

&lt;p&gt;Example if the user is typing for 1 minute straight without pausing then for every 2 sec you would be calling the API.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;As mentioned in the article this is not to explain how the functions work rather to visualise and understand why its used. I would surely recommend you to understand at code level how they work but personally would still use the debounce and throttle provided by lodash library and not to reinvent the wheel.&lt;/p&gt;

&lt;p&gt;If you like the article leave a thumbs up, it would really motivate me to write more. Thanks 👍. &lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
    <item>
      <title>HealthLingo | AI Agents Enabling Multilingual Doctor consultation via WhatsApp</title>
      <dc:creator>Mohamed Ashiq Sultan</dc:creator>
      <pubDate>Fri, 21 Jun 2024 17:57:07 +0000</pubDate>
      <link>https://dev.to/ashiqsultan/healthlingo-consult-doctors-from-whatsapp-in-your-native-language-twilio-with-gpt-544m</link>
      <guid>https://dev.to/ashiqsultan/healthlingo-consult-doctors-from-whatsapp-in-your-native-language-twilio-with-gpt-544m</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/challenges/twilio"&gt;Twilio Challenge v24.06.12&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;People can directly contact doctors from WhatsApp in their native language.&lt;br&gt;
Based on patients query a suitable doctor from the list of doctor will be selected by AI.&lt;br&gt;
The Doctor replies in English while the patient's will receive the reply in their preferred language.&lt;/p&gt;
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi9zr61tlzas43j0n2nka.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi9zr61tlzas43j0n2nka.gif" alt="Small gif showing translation" width="720" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Video explanation of the project and the codebase&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/5pdg0Vm-4X8"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo24nm2gt4cpbo7algwpo.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo24nm2gt4cpbo7algwpo.PNG" alt="whatsapp sandbox link" width="800" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Working of the App
&lt;/h2&gt;

&lt;p&gt;The app consists of two layers&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Business layer&lt;/li&gt;
&lt;li&gt;AI layer&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The business layer is responsible for handling the incoming msg and Database interactions while the AI layer consists of multiple small agents which interacts with Open AI API. I have used MongoDB as the database to store information like patient details, chat summary and doctor information.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F67csuz8czb0pdjx8yz14.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F67csuz8czb0pdjx8yz14.png" alt="explanation of code base" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Twilio and AI
&lt;/h2&gt;

&lt;h3&gt;
  
  
  AI
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Multiple Agents for handling specific tasks using OpenAI's GPT-4o model&lt;/li&gt;
&lt;li&gt;Translate Agent&lt;/li&gt;
&lt;li&gt;Chat Summary Agent&lt;/li&gt;
&lt;li&gt;Two Agents for Details Collection

&lt;ul&gt;
&lt;li&gt;Basic Details Agent&lt;/li&gt;
&lt;li&gt;Medical Details Agent&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Twilio
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Twilio Whatsapp service.
&lt;/li&gt;
&lt;li&gt;Initially the app was deployed as Twilio Functions but was as I added more conditions I was hitting timeouts sometimes. So yeah, I just deployed in AWS using docker. And yes only one Twilio service.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Additional Prize Categories
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Impactful Innovators&lt;/strong&gt;: People who are visiting a country for first time or immigrants who still find it difficult to express especially their medical condition in the foreign language can use this kind of app to communicate with doctors and express their symptoms and conditions.&lt;br&gt;
Also the AI will pick the right doctor based on their condition.&lt;br&gt;
The privacy of both doctor and patient is maintained as no phone numbers are shared.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The vision of such a app in real life would be&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Social service mined Doctors signing up for such a service and give some details about their specialty&lt;/li&gt;
&lt;li&gt;Patients who are looking for answers for some rare or specific condition could potentially find the right doctor and explain their problem in the language they are comfortable with&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you've made it this far, thanks for reading the post! Leaving a like would mean a lot, as it supports my work and encourages me to keep creating more content. Have a great day !&lt;/p&gt;
&lt;h3&gt;
  
  
  GitHub
&lt;/h3&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/ashiqsultan" rel="noopener noreferrer"&gt;
        ashiqsultan
      &lt;/a&gt; / &lt;a href="https://github.com/ashiqsultan/twilio-whatsapp-ai-bot" rel="noopener noreferrer"&gt;
        twilio-whatsapp-ai-bot
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A project developed for dev.to hackathon using Twilio whatsapp service using ChatGPT for AI services
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Twilio Whatsapp Bot&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;This project is created as part of dev.to Twilio Challenge 2024.
&lt;a href="https://dev.to/challenges/twilio" rel="nofollow"&gt;Link to Challenge Page&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The project uses Twilio Whatsapp service along with OpenAI ChatGPT model for AI.&lt;/p&gt;
&lt;p&gt;The concept of the app is to facilitate communication between patients and doctors.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Change log&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;Im need to change the code base from twilio functions to normal express server. This is due to the 10 sec runtime in twilio functions.
There will be lot of file changes as the module imports are different for twilio reusable functions
To refer the code you can checkout this commit: c0797c0&lt;/p&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/ashiqsultan/twilio-whatsapp-ai-bot" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


</description>
      <category>devchallenge</category>
      <category>twiliochallenge</category>
      <category>ai</category>
      <category>twilio</category>
    </item>
    <item>
      <title>Clever Caching | Stock Analysis app using Netlify's fine-grained cache control</title>
      <dc:creator>Mohamed Ashiq Sultan</dc:creator>
      <pubDate>Sun, 12 May 2024 12:53:47 +0000</pubDate>
      <link>https://dev.to/ashiqsultan/clever-caching-a-stock-analysis-app-using-netlifys-fine-grained-cache-control-268b</link>
      <guid>https://dev.to/ashiqsultan/clever-caching-a-stock-analysis-app-using-netlifys-fine-grained-cache-control-268b</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/netlify"&gt;Netlify Dynamic Site Challenge&lt;/a&gt;: Clever Caching&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;I have build a Stock Analysis tool which shows price history, financial data and related News articles for any NYSE listed stock.&lt;br&gt;
&lt;a href="https://github.com/ashiqsultan/market-lens" rel="noopener noreferrer"&gt;Github Link&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Cache Mechanisms used in the Project
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Netlify-Vary&lt;/code&gt;&lt;/strong&gt; headers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Netlify-CDN-Cache-Control&lt;/code&gt;&lt;/strong&gt; headers&lt;/li&gt;
&lt;li&gt;SWR (Stale while revalidate)
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  On-demand Cache Invalidation mechanism using
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;purgeCache()&lt;/code&gt;&lt;/strong&gt; helper function&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Netlify-Cache-Tag&lt;/code&gt;&lt;/strong&gt; headers to purge cache by tags&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ccize5rzabbt2utow2w.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ccize5rzabbt2utow2w.gif" alt="Image description" width="400" height="255"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;



&lt;p&gt;A 10 min video explaining the app and code base.&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/Bodr8fMbzQs"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Link to app&lt;/strong&gt;: &lt;a href="https://market-lens-app.netlify.app/" rel="noopener noreferrer"&gt;https://market-lens-app.netlify.app/&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Cache Status Screen shots
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Initial load of a stock page will have Cache-Status as &lt;code&gt;"Netlify Edge"; fwd=miss&lt;/code&gt;
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkloce37zaub51dbyiphe.PNG" alt="Image description" width="800" height="258"&gt;
&lt;/li&gt;
&lt;li&gt;Further load of the same page will have Cache-Status as &lt;code&gt;"Netlify Edge"; hit&lt;/code&gt;
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Figa5l6rrq8ua2qrup3q9.PNG" alt="Image description" width="800" height="260"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Platform Primitives
&lt;/h2&gt;

&lt;p&gt;Tell us how you leveraged Netlify Cache Control.&lt;/p&gt;

&lt;p&gt;To begin with I firstly configured cache as &lt;code&gt;manual&lt;/code&gt; in the &lt;code&gt;netlify.toml&lt;/code&gt; file for the paths I want to cache.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[[edge_functions]]
  function='news'
  path= '/api/news/:symbol'
  cache='manual'

[[edge_functions]]
  function='financial'
  path= '/api/financial'
  cache='manual'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above file you can see something called &lt;code&gt;symbol&lt;/code&gt;, this stands for &lt;strong&gt;stock ticker symbol&lt;/strong&gt; &lt;em&gt;(Example AAPL is the symbol for Apple INC )&lt;/em&gt;. This symbol plays a key role for the caching mechanism in this project. Let see how. &lt;/p&gt;

&lt;p&gt;For the sake of learning I have used two approaches for querying data&lt;br&gt;
1: Ticker symbol in Path Params.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;api/news/AAPL -&amp;gt; will fetch all news article related to Apple stock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2: Ticker symbol in Query Params.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;api/financial?symbol=AAPL -&amp;gt; will fetch financial data for Apple stock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  1. Caching Response when dynamic value in Path params
&lt;/h3&gt;

&lt;p&gt;For fetching the news data the ticker symbol is passed in the URL's path param. The response header looks like below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const headers = {
  'Content-Type': 'application/json',
  'Cache-Control': 'public, max-age=0, must-revalidate',
  'Netlify-CDN-Cache-Control':'public, max-age=120, stale-while-revalidate=300',
  'Cache-Tag': `${symbol}, ${symbol}-news`,
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I have used &lt;code&gt;Netlify-CDN-Cache-Control&lt;/code&gt; with &lt;strong&gt;stale-while-revalidate&lt;/strong&gt;&lt;br&gt;
The &lt;a href="https://docs.netlify.com/platform/caching/#stale-while-revalidate-directive" rel="noopener noreferrer"&gt;stale-while-revalidate&lt;/a&gt; in the Netlify cache header allows cached content to be served even after it expires (max-age), while simultaneously refreshing the cache in the background. In this case, it allows serving stale content for up to 300 seconds while a new version is fetched and revalidated.&lt;/p&gt;

&lt;p&gt;When the dynamic variable (the stock symbol) is used as a path param you dont have to do much as the symbol is part of the url path.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/api/news/AAPL -&amp;gt; Will have Apple news article Cached
/api/news/MSFT -&amp;gt; -&amp;gt; Will have Microsoft news Article Cached
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The challenge is when symbol is passed in query params. lets see how its cached.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Caching with Netlify-Vary | Dynamic value in Query params
&lt;/h3&gt;

&lt;p&gt;When the symbol is passed in query params then you have to add a custom header &lt;code&gt;Netlify-Vary&lt;/code&gt; in-order to cache the response. The response header looks like below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default async (req: Request, context: Context) =&amp;gt; {
  const parsedUrl = new URL(req.url);
  const queryParams = Object.fromEntries(parsedUrl.searchParams.entries());
  const symbol = queryParams.symbol
...
const headers = {
      'Content-Type': 'application/json',
      'Access-Control-Allow-Origin': '*',
      'Cache-Control': 'public, max-age=0, must-revalidate',
      'Netlify-CDN-Cache-Control':
        'public, max-age=604800 , stale-while-revalidate=2592000',
      'Netlify-Cache-Tag': `${symbol}, ${symbol}-financial`,
      'Netlify-Vary': 'query=symbol',
    };

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This header object is similar to the one we saw above except that we have added an additional header field &lt;strong&gt;Netlify-Vary&lt;/strong&gt; with value &lt;code&gt;query=symbol&lt;/code&gt;. This makes sure to cache response taking the &lt;code&gt;symbol&lt;/code&gt; query param into consideration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/api/financial?symbol=MSFT -&amp;gt; Will cache Microsoft financial data
/api/financial?symbol=TSLA-&amp;gt; Will cache Tesla's financial data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://docs.netlify.com/platform/caching/#vary-by-query-parameter" rel="noopener noreferrer"&gt;More on Netlify-Vary by query params&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  On-demand Cache Purging
&lt;/h2&gt;

&lt;p&gt;I have used Netlify's &lt;a href="https://docs.netlify.com/platform/caching/#use-a-function-with-the-purgecache-helper-to-purge-by-site" rel="noopener noreferrer"&gt;purgeCache() helper&lt;/a&gt; to implement on-demand cache invalidation. I have made this function accessible under the path &lt;code&gt;/manual-purge&lt;/code&gt;&lt;br&gt;
Cache invalidation is one of the hardest things to do in Software development but I'm pretty impressed how Netlify has made it easy to implement with the helper function and cache tags.&lt;/p&gt;
&lt;h3&gt;
  
  
  Cache Tags
&lt;/h3&gt;

&lt;p&gt;You may have noticed a field in my response headers labeled &lt;code&gt;Netlify-Cache-Tag&lt;/code&gt;. This field is crucial for managing cache invalidation behavior effectively.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// news.ts
const header ={
....
'Netlify-Cache-Tag': `${symbol}, ${symbol}-news`,
...
}
// financial.ts
const header ={
....
'Netlify-Cache-Tag': `${symbol}, ${symbol}-financial`,
...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The use of &lt;em&gt;ticker symbol&lt;/em&gt; as tag names allows us to target specific company data for purging without affecting other company data.&lt;/p&gt;

&lt;p&gt;The below tables might help you understand how responses are tagged&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;URL&lt;/th&gt;
&lt;th&gt;Cache tags&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;/api/news/MSFT&lt;/td&gt;
&lt;td&gt;MSFT, MSFT-news&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;/api/financial?symbol=MSFT&lt;/td&gt;
&lt;td&gt;MSFT, MSFT-financial&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;/api/news/TSLA&lt;/td&gt;
&lt;td&gt;TSLA, TSLA-news&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This granular approach ensures that updates or modifications related to particular stocks or financial information are accurately purged without affecting other data.&lt;/p&gt;

&lt;p&gt;Example&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;/manual-purge?tag=MSFT&lt;/code&gt;
Will purge all cached response related to Microsoft i.e News, Financial and Price data&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/manual-purge?tag=MSFT-news&lt;/code&gt;
This will purge only the news data related to Microsoft while other cached data related to Microsoft or any other company is not disturbed.
What's surprising is that the code to purge by tags is relatively simple.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  const url = new URL(req.url);
  const cacheTag = url.searchParams.get('tag');
  await purgeCache({
    tags: [cacheTag],
  });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Below image shows how cached response related to Apple stock are purged&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F00icex1nccnqvtne2ieo.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F00icex1nccnqvtne2ieo.PNG" alt="Image description" width="800" height="272"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Below image shows how only cached response related to Microsoft news are purged&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqckuiwg7yyf7uglxcsqf.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqckuiwg7yyf7uglxcsqf.PNG" alt="Image description" width="800" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Personal Hurdles
&lt;/h3&gt;

&lt;p&gt;I have been searching API providers for stock market data and &lt;br&gt;
settled with Polygon io as the free plan allows 5 calls per minute.&lt;/p&gt;

&lt;p&gt;To be honest, this limitation guided my cache strategy to prioritize minimizing external API calls. By serving cached data for previously accessed stocks, the app successfully avoids redundant calls to the same company.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conslusion
&lt;/h1&gt;

&lt;p&gt;If you have reached this part of the article it would be great if you to leave a like ❤️ for the post as it would motivate me to experiment more stuffs like this.&lt;br&gt;
As someone implementing edge functions and caching for the first time I found Netlify's documentation comprehensive, sparing me the need to rely heavily on YouTube tutorials. The cache-status in response headers simplified debugging not to mention the real time logs in Netlify console. The ability to group and purge cache using Netlify-cache-tags struck me as a particularly cool feature. Looking forward to use them in real life application.&lt;/p&gt;

&lt;p&gt;Thanks to Dev.to team and Netlify for the Hackathon. I learned something new.&lt;/p&gt;

</description>
      <category>netlifychallenge</category>
      <category>devchallenge</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Real-time Location tracking App build with MongoDB Change Streams and Socket.io</title>
      <dc:creator>Mohamed Ashiq Sultan</dc:creator>
      <pubDate>Tue, 06 Dec 2022 12:08:05 +0000</pubDate>
      <link>https://dev.to/ashiqsultan/real-time-location-tracking-app-build-with-mongodb-change-streams-and-socketio-3d4i</link>
      <guid>https://dev.to/ashiqsultan/real-time-location-tracking-app-build-with-mongodb-change-streams-and-socketio-3d4i</guid>
      <description>&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;A Real-time Delivery Service application. The concept is similar to Uber but for carrying packages locally. I have used MongoDB Change Streams to update location and Shipment status notifications in real-time. For this I have to build two UIs one for users and other to simulate delivery associates.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa91fufjgk5yjplo3gqyg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa91fufjgk5yjplo3gqyg.gif" alt="real-time location update" width="600" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Left Window: User App&lt;br&gt;
Right Window: Driver Simulator&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Category Submission:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Real-time&lt;/strong&gt; &lt;a href="https://www.mongodb.com/docs/manual/changeStreams/" rel="noopener noreferrer"&gt;Change Stream&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Video Explanation
&lt;/h3&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/Ydi60M4MrHc"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  App Link
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://delivery-service-frontend.netlify.app/" rel="noopener noreferrer"&gt;User App&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://delivery-associate-simulator.netlify.app/" rel="noopener noreferrer"&gt;Delivery Agent Simulator&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How to Simulate the demo
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: Browser's Geolocation API is 🚫 &lt;strong&gt;not used&lt;/strong&gt; to avoid storing any user location information (GDPR). &lt;br&gt;
To make things easy I have made Chennai, a city in India as the base location. Please simulate the app in the location which gets loaded&lt;br&gt;
🚫 Signup is disabled. Please use the credentials provided below in the post&lt;br&gt;
The Backend is hosted on Render.com free tier so there might be some cold start issues when trying to login&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://delivery-associate-simulator.netlify.app/" rel="noopener noreferrer"&gt;Open the Driver Simulator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Enter this associate id to continue &lt;code&gt;637f9183e03774d5c46ddffc&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://delivery-service-frontend.netlify.app/" rel="noopener noreferrer"&gt;Open the User app&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Use the below credentials to login
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Email: carl@example.com
Password: s24x546olk45edxf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;In the User app click on the "New delivery" button&lt;/li&gt;
&lt;li&gt;Confirm pickup location&lt;/li&gt;
&lt;li&gt;Confirm drop location&lt;/li&gt;
&lt;li&gt;You will see a notification on the driver simulator &lt;/li&gt;
&lt;li&gt;Accept the new delivery request&lt;/li&gt;
&lt;li&gt;In the simulator move the truck icon across the marker (GIF provided below)&lt;/li&gt;
&lt;li&gt;You will see the truck movement on the user map in real-time &lt;/li&gt;
&lt;li&gt;In the simulator Update the delivery status&lt;/li&gt;
&lt;li&gt;You will see the status information getting updated in the user app real time&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Screenshots
&lt;/h3&gt;

&lt;p&gt;Architecture Diagram&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkaqh4xv299ld3g3ji72s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkaqh4xv299ld3g3ji72s.png" alt="Architecture Diagram" width="642" height="352"&gt;&lt;/a&gt;&lt;br&gt;
Live location and Status updates&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1cvac7prsqn0smr3pcjz.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1cvac7prsqn0smr3pcjz.gif" alt="Delivery with live updates" width="120" height="67"&gt;&lt;/a&gt;&lt;br&gt;
Driver Simulator&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkmhtve325dbsdq2mckj0.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkmhtve325dbsdq2mckj0.gif" alt="Driver Simulator" width="600" height="271"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Description
&lt;/h2&gt;

&lt;p&gt;There are three repos to this project.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The Backend&lt;/strong&gt;&lt;br&gt;
The Backend is connected to &lt;a href="https://www.mongodb.com/atlas/database" rel="noopener noreferrer"&gt;MongoDB Atlas&lt;/a&gt; and does CRUD operations on API calls. The Backend service also uses &lt;a href="https://socket.io/" rel="noopener noreferrer"&gt;Socket.io&lt;/a&gt; to handle socket connections. MongoDB Change Streams events are broadcasted via Socket.io. There are three main Change Stream subscriptions in this application&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Delivery Agent's location update change stream to track package&lt;/li&gt;
&lt;li&gt;Shipment Status updates to update status in User UI&lt;/li&gt;
&lt;li&gt;New Shipment Created notification broadcasted to Agents to Accept or Reject a shipment.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;User UI&lt;/strong&gt;&lt;br&gt;
Both frontends are build React and uses &lt;a href="https://leafletjs.com/" rel="noopener noreferrer"&gt;Leaflet&lt;/a&gt; for Maps. The User UI is used to do CRUD events like Signup, Login, Create new deliveries and to show real-time events.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Real-time information updates on Delivery Status. &lt;/li&gt;
&lt;li&gt;Real-time location of the the package being delivered can be seen on the Map&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Delivery Associate Simulator&lt;/strong&gt;&lt;br&gt;
This is used to simulate a delivery agent. This app receives real-time notification when any new delivery gets initiated. Agents can Accept or Reject deliveries and Update delivery status. &lt;br&gt;
The important functionality the simulator provides is the ability to simulate the &lt;strong&gt;GPS location update event of an agent&lt;/strong&gt;. The current location of an Agent is denoted by a Truck Marker on the map. Dragging the marker across the Map emits an event to update the Agent's current location in the DB.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Link to Source Code
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/ashiqsultan/delivery-service-backend" rel="noopener noreferrer"&gt;Backend Main&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ashiqsultan/delivery-service-frontend" rel="noopener noreferrer"&gt;Frontend&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ashiqsultan/delivery-service-associate-simulator" rel="noopener noreferrer"&gt;Driver Simulator&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Permissive License
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;MIT License&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;
&lt;h3&gt;
  
  
  What made me decide to build this particular app?
&lt;/h3&gt;

&lt;p&gt;I wanted to try MongoDB's &lt;strong&gt;Change Stream&lt;/strong&gt; functionality, so I was thinking about building a real-time application. And since MongoDB supports GeoJSON out of the box &lt;strong&gt;I wanted to challenge myself and decided to build a real-time application which uses location data.&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  What inspired me?
&lt;/h4&gt;

&lt;p&gt;Uber and Food delivery Apps. There's a company in India named &lt;strong&gt;Dunzo&lt;/strong&gt; who do similar delivery service.&lt;/p&gt;
&lt;h3&gt;
  
  
  How I built it
&lt;/h3&gt;

&lt;p&gt;I have used MongoDB Atlas free tier for this application. &lt;br&gt;
Something new I learned building this app is &lt;a href="https://www.mongodb.com/docs/manual/changeStreams/" rel="noopener noreferrer"&gt;MongoDB Change Stream&lt;/a&gt;. &lt;br&gt;
I have used Socket.io to create Socket Connection rooms and broadcast events. Socket room name is just the Shipment id and user subscribes to the respective room i.e Shipment id he has created. When there's a MongoDB Change Stream event on Shipment Collection I'm publishing the updated document to the room using the shipmentId which got updated.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Shipment.watch([], watchOptions).on('change', (data: any) =&amp;gt; {
    const fullDocument = data.fullDocument;
    if (data.operationType === 'update') {
      io.to(String(fullDocument._id)).emit(
        socketEvents.SHIPMENT_UPDATED,
        fullDocument
      );
    }
  });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I have used Render to deploy the backend and Netlify to deploy the frontend applications&lt;/p&gt;

&lt;h3&gt;
  
  
  Additional Resources/Info
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.mongodb.com/docs/manual/changeStreams/" rel="noopener noreferrer"&gt;MongoDB Change Stream&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mongoosejs.com/docs/change-streams.html" rel="noopener noreferrer"&gt;Mongoose Change Stream Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://socket.io/" rel="noopener noreferrer"&gt;Socket.IO&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>discuss</category>
    </item>
    <item>
      <title>Real-time Poll app using Redis, WebSocket, Node.js and React</title>
      <dc:creator>Mohamed Ashiq Sultan</dc:creator>
      <pubDate>Sat, 27 Aug 2022 18:53:00 +0000</pubDate>
      <link>https://dev.to/ashiqsultan/real-time-poll-app-built-using-redis-node-and-websocket-md4</link>
      <guid>https://dev.to/ashiqsultan/real-time-poll-app-built-using-redis-node-and-websocket-md4</guid>
      <description>&lt;h3&gt;
  
  
  Overview of My Submission
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Architecture diagram&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F78tgdhxqrh6m83n1silv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F78tgdhxqrh6m83n1silv.png" alt="Architecture diagram" width="800" height="425"&gt;&lt;/a&gt;&lt;br&gt;
For the hackathon I have build a full stack Poll application which uses various Redis modules to implement microservice architecture. The application lets users to create polls and share it with others. Once users cast their vote they can view the results in real-time i.e the poll result graph in Frontend would get updated real-time for all users as votes are being casted.&lt;/p&gt;
&lt;h3&gt;
  
  
  Redis Modules used in the app
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;RedisJSON&lt;/li&gt;
&lt;li&gt;Hash&lt;/li&gt;
&lt;li&gt;List as queue&lt;/li&gt;
&lt;li&gt;pub/sub&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: The detailed documentation can be found in the Readme file of the GitHub repository embedded. This post contains only the minimal info required for hackathon submission.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I have used Node.js for the backend and React for the frontend. I have used Socket.io for implementing Websocket and also used socket.io Redis adapter for multi node deployments thus making this a complete horizontally scalable solution.  &lt;/p&gt;
&lt;h3&gt;
  
  
  Submission Category:
&lt;/h3&gt;

&lt;p&gt;Microservice Mavens (I believe my submission can also be considered under MEAN/MERN Mavericks 😄)&lt;/p&gt;
&lt;h3&gt;
  
  
  Video Explainer of My Project
&lt;/h3&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/LjxmwYUJbwY"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Language Used
&lt;/h3&gt;

&lt;p&gt;TypeScript / Node.js&lt;/p&gt;

&lt;h3&gt;
  
  
  Link to Code
&lt;/h3&gt;

&lt;p&gt;The project consists of three repositories&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://github.com/ashiqsultan/pollboard-backend" rel="noopener noreferrer"&gt;Poll API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ashiqsultan/pollboard-socket-service" rel="noopener noreferrer"&gt;Socket Service&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/ashiqsultan/pollboard-frontend" rel="noopener noreferrer"&gt;Frontend&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/ashiqsultan" rel="noopener noreferrer"&gt;
        ashiqsultan
      &lt;/a&gt; / &lt;a href="https://github.com/ashiqsultan/pollboard-backend" rel="noopener noreferrer"&gt;
        pollboard-backend
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Poll board is a simple poll app build using Redis. This repo is the API service for the application
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Poll Board Real-time Poll app&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;The application lets users to create polls and share it with others. Once users cast their vote they can view the results in real-time i.e the poll result graph in Frontend would get updated real-time for all users as votes are being casted.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Architecture Diagram&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/b92dc65ced1917b03cac717c017e9141d2e228a33841d1b029805d0a85f82b5a/68747470733a2f2f696d6775722e636f6d2f72624545584e472e706e67"&gt;&lt;img src="https://camo.githubusercontent.com/b92dc65ced1917b03cac717c017e9141d2e228a33841d1b029805d0a85f82b5a/68747470733a2f2f696d6775722e636f6d2f72624545584e472e706e67" alt="Architecture Diagram"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Homepage&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/879d7ffc1a7512864b0231a02cb2e4d797dc8f2d1be122c98be623f166a40ed1/68747470733a2f2f696d6775722e636f6d2f6153596a6d78582e706e67"&gt;&lt;img src="https://camo.githubusercontent.com/879d7ffc1a7512864b0231a02cb2e4d797dc8f2d1be122c98be623f166a40ed1/68747470733a2f2f696d6775722e636f6d2f6153596a6d78582e706e67" alt="Homepage"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Vote page&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/1c8f3a529aad8569cc1fb0e67c03ce532ce942e4a3ca766756d21dd3f389b809/68747470733a2f2f692e696d6775722e636f6d2f5a497236756a342e706e67"&gt;&lt;img src="https://camo.githubusercontent.com/1c8f3a529aad8569cc1fb0e67c03ce532ce942e4a3ca766756d21dd3f389b809/68747470733a2f2f692e696d6775722e636f6d2f5a497236756a342e706e67" alt="App Screenshot"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Create new Poll page&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/d76db2c85963d69266dff570daf969f4f207b58f59e48336f38bf863ea554bca/68747470733a2f2f696d6775722e636f6d2f7432344e6879372e706e67"&gt;&lt;img src="https://camo.githubusercontent.com/d76db2c85963d69266dff570daf969f4f207b58f59e48336f38bf863ea554bca/68747470733a2f2f696d6775722e636f6d2f7432344e6879372e706e67" alt="Create new Poll page"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;TODO Overview video (Optional)&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;Here's a short video that explains the project and how it uses Redis:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://youtu.be/LjxmwYUJbwY" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/a23372361a73904b73939929e13aa0f6255a3b32390a8e71a39b10aa3e16ec3a/68747470733a2f2f692e696d6775722e636f6d2f72624545584e472e706e67" alt="IMAGE ALT TEXT HERE"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;How it works&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;The application consists of three repositories&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://github.com/ashiqsultan/pollboard-backend" rel="noopener noreferrer"&gt;Poll API Service (Current Repo)&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ashiqsultan/pollboard-socket-service" rel="noopener noreferrer"&gt;Socket service&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ashiqsultan/pollboard-frontend" rel="noopener noreferrer"&gt;Frontend&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Poll API Service&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;The API server is responsible for all CRUD operations on Poll entity.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Socket Service&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;The socket service uses &lt;a href="https://socket.io" rel="nofollow noopener noreferrer"&gt;Socket.IO&lt;/a&gt; . All users are connect to a socket room. The room name is the poll id they are answering for.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Frontend&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;As you guessed it is the frontend application build with React as a SPA. It…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/ashiqsultan/pollboard-backend" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3&gt;
  
  
  Additional Resources / Info
&lt;/h3&gt;

&lt;p&gt;I have always wanted to work with Redis for a long time and thanks to this Hackathon as it served as the best time to learn and build a small project using Redis. I spent all the weekends of this month to plan the application. I realized that Redis stack provides a lot of modules so I need pick the right one for my needs. Thanks to the detailed docs and resources by the Redis team. Also a special thanks for the RedisInsight team its such a useful tool for Redis beginners I found it similar to the MongoDB Compass.&lt;/p&gt;

&lt;h3&gt;
  
  
  Homepage
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh82fnuoy67glr2e830dj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh82fnuoy67glr2e830dj.png" alt="Homepage" width="800" height="465"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Vote page
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs5hh58pk2l2797clpkg0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs5hh58pk2l2797clpkg0.png" alt="App Screenshot" width="800" height="802"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Create new Poll page
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc456ybaf6o1s1m2d0s0q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc456ybaf6o1s1m2d0s0q.png" alt="Create new Poll page" width="790" height="894"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Check out &lt;a href="https://redis.io/docs/stack/get-started/clients/#high-level-client-libraries" rel="noopener noreferrer"&gt;Redis OM&lt;/a&gt;, client libraries for working with Redis as a multi-model database.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Use &lt;a href="https://redis.info/redisinsight" rel="noopener noreferrer"&gt;RedisInsight&lt;/a&gt; to visualize your data in Redis.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Sign up for a &lt;a href="https://redis.info/try-free-dev-to" rel="noopener noreferrer"&gt;free Redis database&lt;/a&gt;.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>redishackathon</category>
      <category>node</category>
      <category>microservices</category>
      <category>javascript</category>
    </item>
    <item>
      <title>To those who use arrow keys to find old commands.</title>
      <dc:creator>Mohamed Ashiq Sultan</dc:creator>
      <pubDate>Sun, 07 Mar 2021 14:40:36 +0000</pubDate>
      <link>https://dev.to/ashiqsultan/stop-using-arrow-keys-in-terminal-with-these-commands-2g70</link>
      <guid>https://dev.to/ashiqsultan/stop-using-arrow-keys-in-terminal-with-these-commands-2g70</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;history&lt;/li&gt;
&lt;li&gt;history | grep command-name&lt;/li&gt;
&lt;li&gt;Press ctrl + r -&amp;gt; type the command.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope everyone is aware that hitting the arrow keys helps us navigate to recently executed commands but what if you forgot a command you used months before and want to use it now or view all the commands you used relating to git or docker. We will see three commands I often use to achieve this.&lt;/p&gt;

&lt;h1&gt;
  
  
  history
&lt;/h1&gt;

&lt;p&gt;Using this will list all the commands you have executed.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdnq11bb3n9j8p48859at.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdnq11bb3n9j8p48859at.png" alt="Alt Text" width="480" height="289"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Execute a command from History
&lt;/h2&gt;

&lt;p&gt;To execute any one of the commands from the list type&lt;br&gt;
&lt;code&gt;! &amp;lt;history-number&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm6yms6tk3x4zxe10tzpu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm6yms6tk3x4zxe10tzpu.png" alt="Alt Text" width="800" height="73"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  history | grep 
&lt;/h1&gt;

&lt;p&gt;This is just the previous one but we are using the grep to filter the list. &lt;br&gt;
Example, if you want to see only the commands related to docker, you would type&lt;br&gt;
&lt;code&gt;history | grep docker&lt;/code&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frtehcsfg6ydqbidk1zkg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frtehcsfg6ydqbidk1zkg.png" alt="Alt Text" width="506" height="346"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  ctrl + r -&amp;gt; 
&lt;/h1&gt;

&lt;p&gt;Press ctrl + r and start typing the command you knew you have executed months before. The terminal will autocomplete the command.&lt;br&gt;
Example if you haven't used &lt;code&gt;ssh&lt;/code&gt; for sometime and feel lazy about looking the history, you could press ctrl + R and type  ssh The terminal will autocomplete with your recent ssh command.&lt;br&gt;
Example&lt;br&gt;
I have used ctrl + r then typed heroku. The terminal autocompleted with my most recent heroku command&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feo44y0v2h951hx2of7e5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feo44y0v2h951hx2of7e5.png" alt="Alt Text" width="501" height="27"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>linux</category>
      <category>beginners</category>
      <category>devops</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Do you know GeoJSON ?</title>
      <dc:creator>Mohamed Ashiq Sultan</dc:creator>
      <pubDate>Sun, 30 Aug 2020 19:45:10 +0000</pubDate>
      <link>https://dev.to/ashiqsultan/do-you-know-geojson-4gld</link>
      <guid>https://dev.to/ashiqsultan/do-you-know-geojson-4gld</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;For those who don't know, GeoJSON is the standard data format used to store location data and geographical features.&lt;/p&gt;

&lt;h2&gt;
  
  
  Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Terminologies&lt;/li&gt;
&lt;li&gt;Different Geometry types&lt;/li&gt;
&lt;li&gt;Resources&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;GeoJSON is just a JSON object. What makes them a different datatype from plain JSON is its specifications.&lt;/p&gt;

&lt;p&gt;Some databases like Mongo DB has official support for GeoJSON data type. Just like how MongoDB identifies String and Integer types, it identifies and differentiates GeoJSON from normal JSON. It comes with support for indexing and querying GeoJSONs&lt;/p&gt;

&lt;p&gt;In this post, I will cover some of basic concepts of the GeoJSON data type.&lt;/p&gt;

&lt;p&gt;A typical GeoJSON looks like this. &lt;br&gt;
Don't get overwhelmed, we have discussed everything below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "type": "Feature",
    "properties": {},
    "geometry": {
        "type": "Point",
        "coordinates": [-40.078125,70.72897946208789]
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Terminologies
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Coordinates
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A single point in the map is called a coordinate&lt;/strong&gt;&lt;br&gt;
When we are pointing at a location on the map, we are pointing to some longitude and latitude units. We store these sets of units in an array called coordinates.&lt;br&gt;
A coordinates array contains two elements longitude and latitude &lt;br&gt;
NOTE: the order is important&lt;br&gt;
&lt;code&gt;coordinates : [ longitude , latitude ]&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Geometry
&lt;/h2&gt;

&lt;p&gt;Think of geometry as structures. A Geometry defines in what structure the coordinates are stored. &lt;br&gt;
There are certain predefined case-sensitive types of geometry, namely 'Point', 'Line', 'Polygon', and more. We will see them one by one.&lt;br&gt;&lt;br&gt;
A typical geometry looks like below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"geometry": {
    "type": "Point",
    "coordinates": [longitude,latitude]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  "type"
&lt;/h2&gt;

&lt;p&gt;Every geometry must have a property called "type" whose value must only be one of the GeoJSON types mentioned in the &lt;a href="https://tools.ietf.org/html/rfc7946#page-6" rel="noopener noreferrer"&gt;GeoJSON RFC&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are some geometry types that are used to store other geometry types. They are "Feature" and "FeatureCollection" we have discussed about them below.&lt;/p&gt;

&lt;h1&gt;
  
  
  Geometry Types
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Point
&lt;/h2&gt;

&lt;p&gt;A point is a single point or marker on the map. Its geometry contains a single coordinate. This may be used to store individual place like a store.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ff6n29ucnkyli4taxlnqk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ff6n29ucnkyli4taxlnqk.png" alt="Alt Text" width="509" height="290"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"geometry": {
        "type": "Point",
        "coordinates": [
            78.4918212890625,
            22.304343762932216
        ]
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  MultiPoint
&lt;/h2&gt;

&lt;p&gt;As you have guessed by the name, a MultiPoint geometry is used to store multiple points of coordinates in a single geometry. Each element in the coordinates array is itself a coordinate. This may be used to store list of favorite places.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkujkyxsr2tlma8b0y3em.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkujkyxsr2tlma8b0y3em.png" alt="Alt Text" width="593" height="384"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "type": "MultiPoint",
    "coordinates": [
        [80.26951432228088,13.09223800602329],
        [80.27061939239502,13.091631907724683],
        [80.2714991569519,13.09260375427521],
        [80.27050137519836,13.093241199930675]
    ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  LineString
&lt;/h2&gt;

&lt;p&gt;They are a line of points. The JSON structure is the same as that of MultiPoint but since this is of type LinePoint, individual coordinates are treated as a connected line rather than points lying around distinctly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fccko4shrraa8vw1v8e35.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fccko4shrraa8vw1v8e35.png" alt="Alt Text" width="662" height="271"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"geometry": {
    "type": "LineString",
    "coordinates": [
        [80.2122116088867,13.113586344333864],
        [80.25959014892577,13.072121016365408],
        [80.29048919677733,13.114923819297273],
        [80.3207015991211,13.075799674224164],
        [80.33477783203125,13.112248862097216]
    ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  MultiLineString
&lt;/h2&gt;

&lt;p&gt;As the name states it is used to store more than one LineString in a single geometry. Each element of the Coordinates array is like a single LineString Coordinates array.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"geometry":{"type": "MultiLineString",
"coordinates" : [
[
[longitude,latitude],
[longitude,latitude],
[longitude,latitude]  
 ],
[
[longitude,latitude],
[longitude,latitude],
[longitude,latitude]  
 ],
[
[longitude,latitude],
[longitude,latitude],
[longitude,latitude]  
 ],
]}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Polygon
&lt;/h2&gt;

&lt;p&gt;The RFC specification defines polygons are linear rings, in case you are wondering what's a linear ring, so was I.&lt;br&gt;
Let me put it this way, &lt;strong&gt;polygons are any shape which is closed&lt;/strong&gt;, yes literally any shape. In the coven image of this post each letter is a polygon.&lt;/p&gt;

&lt;p&gt;If you understood LineStrings, the RFC specification also defines polygons are closed LineString i.e a polygon is any shape that is closed. A closed LineString means the first and the last coordinate will be the same.&lt;/p&gt;

&lt;p&gt;This may be used to store borders. May it be country's border, city, village or an area's border.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fieeje0g63mb0j4n22bfu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fieeje0g63mb0j4n22bfu.png" alt="Alt Text" width="784" height="430"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"geometry": {
    "type": "Polygon",
    "coordinates": [
        [
            [78.44238281249999,22.62415215809042],
            [77.8436279296875,22.151795575397756],
            [78.486328125,21.764601405743978],
            [79.0521240234375,22.233175265402785],
            [78.44238281249999,22.62415215809042]
        ]
    ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  MultiPolygon
&lt;/h2&gt;

&lt;p&gt;By this time you should have guessed, same like MultiPoint and MultiLine, MultiPolygon is a collection of Polygons. You can use this to store border information of different cities in a state.&lt;/p&gt;

&lt;p&gt;The cover image of this post can be an example of MultiPolygon&lt;/p&gt;

&lt;h2&gt;
  
  
  Feature and FeatureCollection
&lt;/h2&gt;

&lt;p&gt;Here comes the juice. Now you learned about how to store geographical data in various structures like Points, Lines, and Polygons. Now how do you store information for those locations?&lt;/p&gt;

&lt;p&gt;The proper way to store geographical information is by using Feature and FeatureCollection.&lt;/p&gt;

&lt;p&gt;GeoJSON Feature and FeatureCollections are geometry themselves. They are a kind of geometry that is used to store other geometry and properties (information) about that geometry.&lt;/p&gt;

&lt;p&gt;A typical Feature looks like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "type": "Feature",
    "geometry": {
        "type": "Point",
        "coordinates": [-10.0,-10.0]
    },
    "properties": {
        "temperature": "4C",
        "country": "IN",
        "somepropertyName": "Some description"
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above GeoJSON, the geometry can be any of the types we discussed earlier like Point, Line, or Polygon and the properties contain data and information about that geometry.&lt;/p&gt;

&lt;h2&gt;
  
  
  FeatureCollection
&lt;/h2&gt;

&lt;p&gt;As the name suggests a FeatureCollection GeoJSON contains a collection of Features.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvpnatyxbmvz1m4vw84zh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvpnatyxbmvz1m4vw84zh.png" alt="Alt Text" width="444" height="739"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {},
      "geometry": {
        "type": "Point",
        "coordinates": [78.31054687499999,22.39071391683855]
      }
    },
    {
      "type": "Feature",
      "properties": {},
      "geometry": {
        "type": "Point",
        "coordinates": [78.486328125,11.43695521614319]
      }
    },
    {
      "type": "Feature",
      "properties": {},
      "geometry": {
        "type": "Point",
        "coordinates": [77.9150390625,27.176469131898898]
      }
    },
    {
      "type": "Feature",
      "properties": {},
      "geometry": {
        "type": "Point",
        "coordinates": [75.673828125,19.766703551716976]
      }
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Resources
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;RFC secification for GeoJSON&lt;br&gt;
&lt;a href="https://tools.ietf.org/html/rfc7946" rel="noopener noreferrer"&gt;https://tools.ietf.org/html/rfc7946&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Interactive hands on with GeoJSON&lt;br&gt;
&lt;a href="https://geojson.io/" rel="noopener noreferrer"&gt;https://geojson.io/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Best JS Map Library&lt;br&gt;
&lt;a href="https://leafletjs.com/" rel="noopener noreferrer"&gt;Leaflet.js&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>database</category>
      <category>mongodb</category>
      <category>todayilearned</category>
    </item>
    <item>
      <title>Learn Promises to write Asynchronous JavaScript code</title>
      <dc:creator>Mohamed Ashiq Sultan</dc:creator>
      <pubDate>Tue, 18 Feb 2020 09:47:37 +0000</pubDate>
      <link>https://dev.to/ashiqsultan/learn-promises-to-write-asynchronous-javascript-code-j74</link>
      <guid>https://dev.to/ashiqsultan/learn-promises-to-write-asynchronous-javascript-code-j74</guid>
      <description>&lt;h4&gt;
  
  
  What you will learn
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Creating Promises&lt;/li&gt;
&lt;li&gt;Promise Executor function&lt;/li&gt;
&lt;li&gt;resolve and reject in Promise&lt;/li&gt;
&lt;li&gt;Consuming Promises&lt;/li&gt;
&lt;li&gt;Chaining Promises&lt;/li&gt;
&lt;li&gt;Catching errors in Promise&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Disclaimer : I have used only arrow functions.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why write Async code anyway?
&lt;/h1&gt;

&lt;p&gt;JavaScript is a single-threaded programming language which means only a single statement is executed at a time. This means until a statement is completely executed it will not go to the next line of code.&lt;br&gt;
This is a problem if you have a code snippet that takes a long time to complete such as an API call or reading a file from the disk.&lt;/p&gt;

&lt;p&gt;To solve this we write asynchronous JavaScript code.&lt;/p&gt;
&lt;h1&gt;
  
  
  Creating New Promises
&lt;/h1&gt;

&lt;p&gt;Promises are easy to create. Just create a function and return a new Promises&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const longOperation = () =&amp;gt; {
         return new Promise ()
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A promise takes an executor function as a parameter which again takes two parameters &lt;code&gt;resolve&lt;/code&gt; and &lt;code&gt;reject&lt;/code&gt; the code is easier to understand than my words.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const longOperation = () =&amp;gt; {
    return new Promise((resolve, reject) =&amp;gt; {
        // executor function
        // your business logic here
    });
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Executor function
&lt;/h2&gt;

&lt;p&gt;This is the place where you would write the synchronous code (or any code) which you want to run in the background. It has two arguments &lt;code&gt;resolve&lt;/code&gt; and &lt;code&gt;reject&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;code&gt;resolve&lt;/code&gt; and &lt;code&gt;reject&lt;/code&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Think of these as return statements in a function. The Executor function should execute either resolve or reject based on your business logic. When the code inside the Executor function runs like expected without any errors, then execute the &lt;strong&gt;resolve&lt;/strong&gt; function with the value you want to return. If anything goes wrong like 'file not found' or 'network error' return the error message using the &lt;strong&gt;reject&lt;/strong&gt; function. I hope the following code will make it clear.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const longOperation = (a, b) =&amp;gt; {
    return new Promise((resolve, reject) =&amp;gt; {
        // executor function
        try {
            const result = a * b;
            resolve(result);
        } catch (error) {
            reject(`Error resolving promise ${error}`);
        }
    });
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;
  
  
  Same example using  if..else
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   const longOperation = (a, b) =&amp;gt; {
        return new Promise((resolve, reject) =&amp;gt; {
            // executor function
            const result = a * b;
            if(true){
                resolve(result);
            }
            else{
                reject(`Error resolving promise ${error}`);
            }
        });
    };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Again
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;resolve(returnValue)&lt;/code&gt; : Use this to return the result from successful execution of the business logic.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;reject(errorValue)&lt;/code&gt; : Use this when your logic fails and you want to throw errors. This will trigger the catch block when the function is called inside a &lt;code&gt;try...catch&lt;/code&gt; block or the &lt;code&gt;.catch()&lt;/code&gt; when you consume your promise.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Consuming Promise
&lt;/h1&gt;

&lt;p&gt;A promise can be consumed in two ways&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;.then().catch()&lt;/code&gt; function&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;async / await&lt;/code&gt; function&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Method 1 &lt;code&gt;.then().catch()&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;This is the simplest way to consume a promise.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;longOperation(5,6).then().catch()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;When the Promise &lt;code&gt;longOperation&lt;/code&gt; runs without any errors the &lt;code&gt;.then()&lt;/code&gt; is executed. If there are any errors, the &lt;code&gt;.catch()&lt;/code&gt; is executed&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;longOperation(5, 5)
    .then(result =&amp;gt; console.log(result))
    .catch(err =&amp;gt; console.log(err));

console.log('This will be logged first'); // to demonstrate that promise is non-blocking

Output
This will be logged first
25
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;
  
  
  Explanation
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;.then()&lt;/code&gt; is executed if longOperation executes without any error, in other words, if the Promise is &lt;code&gt;resolve&lt;/code&gt;d&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;.catch()&lt;/code&gt; is executed if longOperation  &lt;code&gt;reject&lt;/code&gt;s the Promise&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;result&lt;/code&gt; argument will contain the value passed to the &lt;code&gt;resolve&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;err&lt;/code&gt; argument will contain the value passed to the &lt;code&gt;reject&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note : The code &lt;code&gt;console.log('This will be logged first');&lt;/code&gt; is only used to demonstrate that Promises are non-blocking. Though it is callafter the &lt;code&gt;longOperation&lt;/code&gt; function call, it's being logged first in the console, this is because the &lt;code&gt;longOperation&lt;/code&gt; returns a Promise which runs in the background which makes JS available to execute the remaining code.&lt;/p&gt;
&lt;h2&gt;
  
  
  Method 2 &lt;code&gt;async / await&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Using &lt;code&gt;async / await&lt;/code&gt; is like sugar-coating what we saw earlier. Instead of using &lt;code&gt;.then()&lt;/code&gt; we are using a syntax which looks like synchronous code. &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const main = async () =&amp;gt; {
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Just declare a function like you will usually do.&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;async&lt;/code&gt; keyword before the parenthesis of the arrow function. This will allow the function to use &lt;code&gt;await&lt;/code&gt; keyword inside it.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const main = async () =&amp;gt; {
        try {
            const result = await longOperation(10, 2);
            console.log(result);
        } catch (error) {
            console.log(error)
        }
    };
    main()

    console.log('This will be logged first'); // to demonstrate that promise is non-blocking

    Output
    This will be logged first
    20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Explanation
&lt;/h4&gt;

&lt;p&gt;The variable &lt;code&gt;result&lt;/code&gt; will contain the resolved value from the promise &lt;code&gt;longOperation&lt;/code&gt; (i.e) it will contain the value passed inside the &lt;code&gt;resolve()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When something goes wrong with &lt;code&gt;longOperation&lt;/code&gt; then the catch block is executed. The error variable contains the value passed inside the &lt;code&gt;reject()&lt;/code&gt; of the Promise.&lt;/p&gt;

&lt;p&gt;Note: If you are using async...await then you should always consume promises inside a try...catch block.&lt;/p&gt;

&lt;h1&gt;
  
  
  Chaining Promises
&lt;/h1&gt;

&lt;p&gt;Some times you want to chain Promises (i.e) you want to execute another Promise after completion of a Promise.&lt;/p&gt;

&lt;h3&gt;
  
  
  Chaining Promise using &lt;code&gt;.then()&lt;/code&gt;
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;longOperation(5, 5)
    .then(result =&amp;gt; longOperation(10, result)) // multiply result by 10
    .then(result =&amp;gt; longOperation(100, result)) // multiply result by 100
    .then(result =&amp;gt; console.log(result)) // console log final result
    .catch(err =&amp;gt; console.log(err));

console.log('This will be logged first'); // to demonstrate that promise is non-blocking

OUTPUT
This will be logged first
25000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Note: Since I'm lazy to write imaginative Promise functions, I'm using the same longOperation to mimic a new promise. In reality, you will be calling different promises after the successful execution of one. &lt;/p&gt;

&lt;p&gt;If any Promise in the chain throws an error then the &lt;code&gt;.catch()&lt;/code&gt; is executed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Chaining Promise using &lt;code&gt;async / await&lt;/code&gt;
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const main = async () =&amp;gt; {
    try {
        const result1 = await longOperation(10, 5);
        const result2 = await longOperation(100, result1); // multiply result1 with 100
        const result3 = await longOperation(1000, result2); // multiply result2 with 1000
        console.log(result3); // only executed after all the Promises are resolved
    } catch (error) {
        console.log(error);
    }
};

main();

console.log('This will be logged first'); // to demonstrate that promise is non-blocking

This will be logged first
5000000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Using async / await will make your code look tidy and readable unlike .then() in which you would have to write a lot of callbacks.&lt;/p&gt;

&lt;p&gt;The catch block will be executed when any of the Promise throws an error.&lt;/p&gt;

&lt;h1&gt;
  
  
  Catching Errors in Promise
&lt;/h1&gt;

&lt;p&gt;As we saw earlier, when any of the Promise executes the &lt;code&gt;reject()&lt;/code&gt; function then the catch block is executed. To demonstrate this we will create a new Promise.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const checkAndMultiply = (a, b) =&amp;gt; {
    return new Promise((resolve, reject) =&amp;gt; {
        // executor function
        if (isNaN(a) || isNaN(b)) {
            const error = 'Error: inputs are not numbers';
            reject(error);
        }
        const result = a * b;
        resolve(result);
    });
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;checkAndMultiply&lt;/code&gt; is a Promise which will only resolve if both the inputs passed to it are numbers else it will throw an error. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const main = async () =&amp;gt; {
    try {
        const result1 = await longOperation(10, 5);
        const result2 = await checkAndMultiply("text", result1);
        const result3 = await checkAndMultiply(100, result2);
        console.log(result3);
    } catch (error) {
        console.log(error);
    }
};

main();
console.log('This will be logged first');


Output
This will be logged first
Error: inputs are not numbers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The first Promise &lt;code&gt;longOperation&lt;/code&gt; is resolved successfully &lt;br&gt;
The second Promise &lt;code&gt;checkAndMultiply&lt;/code&gt; take string as one of its argument. So the Promise is rejected and the catch block is called without executing the next Promise in the code.&lt;/p&gt;

&lt;p&gt;I hope this article might have helped you to understand Promises in JavaScript better. You can read more about Promise from MDN Web Docs.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>tutorial</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
