<?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: Fahim Ahammed Firoz</title>
    <description>The latest articles on DEV Community by Fahim Ahammed Firoz (@fahimahammed).</description>
    <link>https://dev.to/fahimahammed</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1196293%2Fa1f8d64f-0d98-495c-ab08-c9127998fe69.jpeg</url>
      <title>DEV Community: Fahim Ahammed Firoz</title>
      <link>https://dev.to/fahimahammed</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/fahimahammed"/>
    <language>en</language>
    <item>
      <title>What I Built</title>
      <dc:creator>Fahim Ahammed Firoz</dc:creator>
      <pubDate>Sat, 31 Oct 2026 17:40:20 +0000</pubDate>
      <link>https://dev.to/fahimahammed/what-i-built-590o</link>
      <guid>https://dev.to/fahimahammed/what-i-built-590o</guid>
      <description>&lt;p&gt;*This is a submission for the &lt;a href="https://dev.to/mlh-hackathon"&gt;MLH x DEV Writing Challenge*&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;During the hackathon, my team and I built &lt;strong&gt;EcoSync&lt;/strong&gt; (name your project here if different), a real-time web application designed to help communities track, report, and gamify local environmental cleanups and recycling efforts.&lt;/p&gt;

&lt;p&gt;The idea came from seeing how difficult it is for grassroots environmental groups to coordinate volunteer turnouts and visualize their measurable impact. EcoSync allows users to drop pins on local areas that need attention, join nearby cleanup events, log waste collected, and earn activity badges.&lt;/p&gt;

&lt;p&gt;Building it in under 36 hours pushed our limits. We learned how to rapidly design and deploy a full-stack product under pressure, handle state management efficiently in real-time, and balance feature ambition with shipping a functional MVP before the deadline.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Live Application:&lt;/strong&gt; &lt;a href="https://your-demo-link-here.com" rel="noopener noreferrer"&gt;https://ecosync-demo.vercel.app&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Repository:&lt;/strong&gt; &lt;a href="https://www.google.com/search?q=https://github.com/your-username/ecosync" rel="noopener noreferrer"&gt;https://github.com/your-username/ecosync&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Here is a quick walkthrough of the core workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;User Dashboard:&lt;/strong&gt; Displays nearby cleanup initiatives and active community boards.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interactive Map:&lt;/strong&gt; Shows geo-tagged cleanup spots with urgency indicators.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Impact Tracker:&lt;/strong&gt; Lets organizers log the weight/volume of waste collected, automatically updating the event leaderboard.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Partner Technologies
&lt;/h2&gt;

&lt;p&gt;To power the app reliably and quickly, we integrated two MLH partner technologies:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. MongoDB Atlas
&lt;/h3&gt;

&lt;p&gt;We needed a flexible, scalable document database to handle dynamic event locations, volunteer profiles, and status updates. We deployed a managed MongoDB Atlas cluster to store:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User authentication and badge records&lt;/li&gt;
&lt;li&gt;Dynamic geospatial coordinates for cleanup pins&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using MongoDB’s geospatial queries (&lt;code&gt;$near&lt;/code&gt; and &lt;code&gt;$geoWithin&lt;/code&gt;), we were able to quickly fetch cleanup tasks within a 5-mile radius of a user’s current coordinates. Atlas made the setup effortless, letting us connect directly through Mongoose without dealing with manual database server maintenance.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Twilio (Messaging API)
&lt;/h3&gt;

&lt;p&gt;To keep volunteers updated without requiring them to keep the web app open, we integrated the Twilio SMS API. When an organizer changes an event status or issues an urgent weather alert, registered volunteers receive an instant SMS notification. Setting up the Twilio Node.js SDK took less than an hour, and the documentation made testing edge-case alerts seamless.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hackathon Experience
&lt;/h2&gt;

&lt;p&gt;I participated in &lt;strong&gt;Hack the North&lt;/strong&gt; (or insert your hackathon's name here), and the energy was electric from start to finish. Collaborating across time zones with teammates who brought distinct skills in UI/UX, backend logic, and system design made the long hours genuinely fun.&lt;/p&gt;

&lt;p&gt;The highlight of the event was the late-night debugging session around 3:00 AM—when our API routes were throwing silent CORS errors right before our first planned sleep break. Solving that together over a shared Discord call, finally seeing the live data render on screen, and making the submission minutes before the portal closed is something I won’t forget.&lt;/p&gt;

&lt;p&gt;A massive thank you to Major League Hacking (MLH), DEV, and the event mentors for organizing such an inspiring space to build, break, and learn.&lt;/p&gt;

</description>
      <category>mlhacks</category>
      <category>devchallenge</category>
      <category>hackathon</category>
    </item>
    <item>
      <title>Private Notes AI: A Ghost That Remembers Your Past</title>
      <dc:creator>Fahim Ahammed Firoz</dc:creator>
      <pubDate>Sat, 31 Oct 2026 17:37:08 +0000</pubDate>
      <link>https://dev.to/fahimahammed/private-notes-ai-a-ghost-that-remembers-your-past-4dc4</link>
      <guid>https://dev.to/fahimahammed/private-notes-ai-a-ghost-that-remembers-your-past-4dc4</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week4-2026-10-26"&gt;Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;What if you could talk to your past self?&lt;/p&gt;

&lt;p&gt;We write hundreds of notes, save random thoughts, document ideas, and sometimes forget where we put them. Eventually, those memories become digital ghosts buried somewhere in our devices.&lt;/p&gt;

&lt;p&gt;That's why I came up with &lt;strong&gt;Private Notes AI&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Private Notes AI is an AI-powered personal memory assistant that helps users interact with their own notes using natural language.&lt;/p&gt;

&lt;p&gt;Instead of manually searching through hundreds of notes, you can simply ask questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"What was that project idea I wrote down last month?"&lt;/li&gt;
&lt;li&gt;"Did I ever make notes about learning Kubernetes?"&lt;/li&gt;
&lt;li&gt;"Find the technical decisions I made for my previous project."&lt;/li&gt;
&lt;li&gt;"What were my goals for this year?"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The AI searches your personal knowledge base and brings relevant memories back to life.&lt;/p&gt;

&lt;p&gt;The idea behind the project perfectly fits this week's theme: &lt;strong&gt;Ghost in the Machine&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A little ghost that lives inside your machine and remembers things you might have forgotten.&lt;/p&gt;

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

&lt;p&gt;[Add your deployed demo URL here]&lt;/p&gt;

&lt;p&gt;[Add a demo video here]&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;GitHub Repository: [Add your GitHub repository URL here]&lt;/p&gt;

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

&lt;p&gt;The main idea was to build an AI application where open-source AI isn't just an additional feature. It's the actual engine behind the experience.&lt;/p&gt;

&lt;p&gt;The planned architecture includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Open-weight LLM:&lt;/strong&gt; For understanding questions and generating contextual responses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ollama:&lt;/strong&gt; For running AI models locally.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Embeddings:&lt;/strong&gt; To convert personal notes into searchable vector representations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vector Search:&lt;/strong&gt; To retrieve relevant memories based on semantic similarity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend:&lt;/strong&gt; To manage notes, indexing, and AI interactions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frontend:&lt;/strong&gt; To provide a simple conversational interface.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The workflow is straightforward:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Users create or import their personal notes.&lt;/li&gt;
&lt;li&gt;Notes are converted into embeddings.&lt;/li&gt;
&lt;li&gt;Embeddings are stored in a searchable knowledge base.&lt;/li&gt;
&lt;li&gt;Users ask questions in natural language.&lt;/li&gt;
&lt;li&gt;Relevant notes are retrieved and provided as context to the local LLM.&lt;/li&gt;
&lt;li&gt;The model generates an answer based on the user's own information.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The goal is to make the entire AI workflow possible without depending on a proprietary AI API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;This is probably the most important part of this project.&lt;/p&gt;

&lt;p&gt;Personal notes can contain almost anything: private thoughts, passwords accidentally written down, business ideas, project plans, personal experiences, and important memories.&lt;/p&gt;

&lt;p&gt;Sending all of that information to an external AI service isn't always a good idea.&lt;/p&gt;

&lt;p&gt;With open-source AI and local inference, we get more control over our data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Privacy:&lt;/strong&gt; Personal information can stay on the user's own machine instead of being sent to an external AI provider.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Freedom:&lt;/strong&gt; We can experiment with different open-weight models and choose the one that works best.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No vendor lock-in:&lt;/strong&gt; The application doesn't have to depend on a single company's API, pricing, or availability.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Offline possibilities:&lt;/strong&gt; Once the model and required resources are downloaded, the core AI experience can work without an internet connection.&lt;/p&gt;

&lt;p&gt;For me, open innovation is not just about using free software. It's about having the freedom to understand, modify, improve, and control the technology we're building with.&lt;/p&gt;

&lt;p&gt;A private memory assistant should belong to its user, not to an AI company.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Agent Session
&lt;/h2&gt;

&lt;p&gt;[Add your DevRelay session link here]&lt;/p&gt;

&lt;h2&gt;
  
  
  The Spirit of It
&lt;/h2&gt;

&lt;p&gt;We often think technology is about remembering more things.&lt;/p&gt;

&lt;p&gt;But sometimes, the real problem is that we forget the things that matter.&lt;/p&gt;

&lt;p&gt;An old project idea, a random thought at 2 AM, a solution to a problem we struggled with months ago, or a goal we once promised ourselves to achieve.&lt;/p&gt;

&lt;p&gt;Imagine asking your computer about something you wrote two years ago and getting an answer instantly.&lt;/p&gt;

&lt;p&gt;It's almost like having a conversation with your past self.&lt;/p&gt;

&lt;p&gt;Maybe that's what a ghost in the machine really is.&lt;/p&gt;

&lt;p&gt;Not something that haunts you, but something that remembers you.&lt;/p&gt;




&lt;h1&gt;
  
  
  Prize Categories
&lt;/h1&gt;

&lt;p&gt;[Add applicable partner prize categories here]&lt;/p&gt;

&lt;p&gt;Thanks to the DEV team and all the partners for organizing this challenge. Building something around open-source AI has been a great opportunity to explore what's possible beyond closed AI APIs.&lt;/p&gt;

&lt;p&gt;Happy Hacktoberfest! 👻&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>DocuFlow AI: Turn Any Codebase into a Client-Ready Technical Audit</title>
      <dc:creator>Fahim Ahammed Firoz</dc:creator>
      <pubDate>Mon, 19 Oct 2026 07:29:54 +0000</pubDate>
      <link>https://dev.to/fahimahammed/docuflow-ai-turn-any-codebase-into-a-client-ready-technical-audit-97p</link>
      <guid>https://dev.to/fahimahammed/docuflow-ai-turn-any-codebase-into-a-client-ready-technical-audit-97p</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week2-2026-10-12"&gt;Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;Every developer knows the challenge of joining a project with thousands of lines of undocumented code, unclear architecture, and no reliable API reference. For freelancers and agencies, understanding an unfamiliar codebase can consume hours of unpaid discovery work before a project even begins.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DocuFlow AI&lt;/strong&gt; is an autonomous codebase documentation and architecture analysis engine designed to turn that problem into a sellable service.&lt;/p&gt;

&lt;p&gt;It helps developers, freelance consultants, and software agencies analyze existing repositories and generate professional, client-ready technical documentation.&lt;/p&gt;

&lt;p&gt;With DocuFlow AI, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Generate architecture overviews:&lt;/strong&gt; Understand the technology stack, project structure, major components, and dependencies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create interactive architecture diagrams:&lt;/strong&gt; Generate Mermaid-based component and sequence diagrams.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Discover APIs and code symbols:&lt;/strong&gt; Catalog routes, functions, classes, interfaces, and other important code structures.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit operations and security:&lt;/strong&gt; Identify potential security issues, missing validations, configuration concerns, and technical debt.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Export client-ready reports:&lt;/strong&gt; Package findings into Markdown documentation and branded technical audit deliverables.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is simple: help developers spend less time reverse-engineering code and more time delivering valuable work.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Side Hustle Opportunity
&lt;/h3&gt;

&lt;p&gt;DocuFlow AI makes it easier to offer codebase audits as a freelance service, particularly during client onboarding, legacy system handoffs, and technical due diligence.&lt;/p&gt;

&lt;p&gt;Potential business models include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One-time audits:&lt;/strong&gt; $49 per report.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Freelancer and agency subscriptions:&lt;/strong&gt; $199/month.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise on-premise CLI:&lt;/strong&gt; $499/seat/year.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentation automation:&lt;/strong&gt; GitHub Actions and CI/CD integrations that keep technical documentation updated as code changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are proposed pricing models, not verified revenue or customer results.&lt;/p&gt;

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

&lt;p&gt;The project is designed to run locally through an interactive web dashboard or a command-line interface.&lt;/p&gt;

&lt;p&gt;The dashboard provides a place to explore generated documentation, architecture diagrams, and code analysis results.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Run it locally:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install dependencies&lt;/span&gt;
pnpm &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="c"&gt;# Start the dashboard&lt;/span&gt;
pnpm start

&lt;span class="c"&gt;# Open http://localhost:3000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For CLI usage:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Analyze a repository with Gemini&lt;/span&gt;
pnpm cli /path/to/target-repo &lt;span class="nt"&gt;--key&lt;/span&gt; YOUR_GEMINI_KEY

&lt;span class="c"&gt;# Run without an external AI API key&lt;/span&gt;
pnpm cli /path/to/target-repo &lt;span class="nt"&gt;--provider&lt;/span&gt; heuristic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The heuristic mode provides a no-API-key alternative for structural analysis and documentation generation. It should not be confused with local LLM inference.&lt;/p&gt;
&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;The project is built around a modular architecture that separates repository analysis, AI-powered synthesis, and documentation delivery.&lt;/p&gt;

&lt;p&gt;The intended workflow is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ingest a local repository, ZIP archive, or sample project.&lt;/li&gt;
&lt;li&gt;Parse the file hierarchy, code symbols, routes, and dependencies.&lt;/li&gt;
&lt;li&gt;Build structured context for documentation and audit generation.&lt;/li&gt;
&lt;li&gt;Generate architecture explanations, diagrams, API references, and audit findings.&lt;/li&gt;
&lt;li&gt;Export the results as reusable technical documentation and client handoff reports.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Explore the project through the code repository and running demo linked with the submission.&lt;/p&gt;
&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;DocuFlow AI uses a multi-stage pipeline to transform source code into structured technical insights.&lt;/p&gt;
&lt;h3&gt;
  
  
  Stage 1: Repository Analysis
&lt;/h3&gt;

&lt;p&gt;The first stage walks through the codebase, identifies files and technologies, extracts relevant code structures, and maps dependencies.&lt;/p&gt;

&lt;p&gt;This structured analysis reduces the need to send entire source files to an AI model when only specific symbols or relationships are relevant.&lt;/p&gt;
&lt;h3&gt;
  
  
  Stage 2: AI-Powered Documentation
&lt;/h3&gt;

&lt;p&gt;The second stage synthesizes the extracted context into several deliverables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Executive architecture summaries.&lt;/li&gt;
&lt;li&gt;Component and sequence diagrams using Mermaid.&lt;/li&gt;
&lt;li&gt;API references and symbol catalogs.&lt;/li&gt;
&lt;li&gt;Operational documentation and security review findings.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The AI provider layer supports a flexible approach to inference, allowing users to choose a provider based on their privacy, hardware, and quality requirements.&lt;/p&gt;
&lt;h3&gt;
  
  
  Stage 3: Documentation and Reporting
&lt;/h3&gt;

&lt;p&gt;The final stage presents the generated results in a web dashboard and supports exporting documentation for further editing, sharing, and client delivery.&lt;/p&gt;

&lt;p&gt;The goal is not merely to produce a summary of source code. It is to create documentation that a developer or consultant can use as a practical engineering deliverable.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;Open innovation is central to DocuFlow AI because source code is often one of a company's most sensitive assets.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Privacy and Local-First Analysis
&lt;/h3&gt;

&lt;p&gt;Client repositories can contain proprietary algorithms, internal APIs, business logic, and confidential configuration details.&lt;/p&gt;

&lt;p&gt;An open-source analysis pipeline can inspect repository structure locally without requiring the source code to be uploaded to an external service.&lt;/p&gt;

&lt;p&gt;When paired with a compatible local model, the entire analysis and inference workflow can operate without an external AI API connection, provided the required models and dependencies are already installed.&lt;/p&gt;

&lt;p&gt;This is especially valuable for consultants working under NDAs and teams with strict data governance requirements.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Open-Weight Models and Flexible Inference
&lt;/h3&gt;

&lt;p&gt;DocuFlow AI is designed to support local inference through tools such as Ollama and compatible OpenAI-style endpoints, with open-weight coding models such as Qwen2.5-Coder and DeepSeek-Coder as potential choices.&lt;/p&gt;

&lt;p&gt;For users who prefer cloud inference, the architecture also accommodates Google Gemini.&lt;/p&gt;

&lt;p&gt;This flexibility lets users choose between local privacy, available hardware, inference quality, and cloud convenience instead of depending entirely on a single proprietary provider.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Lower Operating Costs
&lt;/h3&gt;

&lt;p&gt;Traditional AI-powered auditing services can incur recurring API costs, especially when analyzing large repositories through multiple generation passes.&lt;/p&gt;

&lt;p&gt;Local inference can eliminate per-token API charges, although hardware, electricity, maintenance, and execution time still have costs.&lt;/p&gt;

&lt;p&gt;That creates an opportunity for freelancers to build repeatable audit workflows and improve their margins without making every report dependent on a paid AI endpoint.&lt;/p&gt;
&lt;h3&gt;
  
  
  4. A Foundation Others Can Extend
&lt;/h3&gt;

&lt;p&gt;An open and modular approach makes it easier to extend the tool with additional language analyzers, model providers, report formats, and CI/CD integrations.&lt;/p&gt;

&lt;p&gt;The long-term vision is to make high-quality codebase documentation more accessible to individual developers and small agencies, not just organizations with dedicated architecture teams.&lt;/p&gt;
&lt;h2&gt;
  
  
  My Agent Session
&lt;/h2&gt;

&lt;p&gt;I recorded and saved the agentic building process using DevRelay so that judges and other developers can explore the process behind the project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://dev.to/agent_sessions/building-docuflow-ai-autonomous-codebase-documentation-architecture-engine-pbjbtd"&gt;View the complete DocuFlow AI agent session on DEV.to&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The session provides an opportunity to inspect the prompts, tool calls, implementation workflow, and code changes involved in building the project.&lt;/p&gt;

&lt;p&gt;You can also explore the interactive session using the embedded agent session below.&lt;/p&gt;


&lt;div class="ltag-agent-session"&gt;
  &lt;div class="agent-session-header"&gt;
    
    &lt;span class="agent-session-tool-icon-badge" title="Gemini CLI"&gt;
&lt;/span&gt;
    &lt;span class="agent-session-title"&gt;Building DocuFlow AI: Autonomous Codebase Documentation &amp;amp; Architecture Engine&lt;/span&gt;
  &lt;/div&gt;

  &lt;div class="agent-session-scroll"&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Side Hustle Hackathon: Build something with open-source AI at its core that someone would actually pay for. We chose to build DocuFlow AI: an autonomous codebase documentation generator &amp;amp; architecture auditing engine.&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Researched the technical pain point: developers &amp;amp; freelancers spend 25-35% of their billable hours deciphering legacy codebases, reverse-engineering routes, and drawing architecture diagrams. Architected a multi-stage pipeline:&lt;br&gt;
1. Open-Source AST Parser (extracts symbols, routes, classes, imports)&lt;br&gt;
2. Dual-Engine LLM Orchestrator (Google Gemini 1M+ context + Local Open-Weights via Ollama / Qwen2.5-Coder)&lt;br&gt;
3. Interactive Web Dashboard with live Mermaid.js diagram rendering and Client Handoff Export.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-writetofile"&gt;write_to_file&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;server/agent/parser.js&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;server/agent/parser.js&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Created codebase AST parser with regex tokenizers for JS/TS/Python/Go/Rust&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-writetofile"&gt;write_to_file&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;server/agent/pipeline.js&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;server/agent/pipeline.js&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Created 5-stage documentation pipeline orchestrator&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Add Google Gemini API client, local open-weight model runner, prepackaged demo samples, and an interactive frontend dashboard with Mermaid diagrams.&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Implemented Gemini API client with automatic fallback, Ollama connector for air-gapped local inference, Express backend with ZIP upload, and a Tailwind + Lucide + Mermaid.js web application. Tested the CLI runner and verified zero-token heuristic generation.&lt;/p&gt;

                &lt;/div&gt;
              &lt;div class="agent-session-tool-call"&gt;
                
                  &lt;span class="agent-session-chevron"&gt;▸&lt;/span&gt;
                  &lt;span class="tool-name tool-name-runcommand"&gt;run_command&lt;/span&gt;
                    &lt;span class="tool-input-preview"&gt;node bin/repodoc.js server/samples/ecommerce-api --provider heuristic&lt;/span&gt;
                
                &lt;div class="agent-session-tool-detail"&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Input&lt;/div&gt;
                      &lt;pre class="agent-session-pre agent-session-terminal"&gt;&lt;code&gt;$ node bin/repodoc.js server/samples/ecommerce-api --provider heuristic&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                    &lt;div class="tool-section"&gt;
                      &lt;div class="tool-section-label"&gt;Output&lt;/div&gt;
                      &lt;pre class="agent-session-pre"&gt;&lt;code&gt;Successfully generated CODEBASE_DOCUMENTATION.md with 6 files, 170 lines, 9 symbols, and Mermaid component &amp;amp; sequence diagrams.&lt;/code&gt;&lt;/pre&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-user"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-user"&gt;
          You
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Add UI screenshots to README.md and install DevRelay to save the agent session.&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="agent-session-message agent-session-assistant"&gt;
        &lt;div class="agent-session-role-badge agent-session-role-assistant"&gt;
          Agent
        &lt;/div&gt;
        &lt;div class="agent-session-content"&gt;
                &lt;div class="agent-session-text"&gt;
                  &lt;p&gt;Embedded all 4 product screenshots (Codebase Overview, Architecture &amp;amp; Mermaid diagrams, API &amp;amp; Endpoint Finder, and Code Health Audit) into README.md. Installed and registered DevRelay MCP server and skills.&lt;/p&gt;

                &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
  &lt;/div&gt;

  &lt;div class="agent-session-footer"&gt;
    &lt;span class="agent-session-meta"&gt;
        6 of 6 messages
    &lt;/span&gt;
  &lt;/div&gt;
&lt;/div&gt;



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

&lt;p&gt;&lt;strong&gt;Primary category:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;DocuFlow AI focuses on turning open-source AI capabilities into a practical developer tool with a clear path toward a sustainable freelance or agency service.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;The bigger idea:&lt;/strong&gt; Documentation should not be an afterthought or an expensive manual process. With structured code analysis and flexible AI inference, developers can turn undocumented codebases into understandable systems and valuable client deliverables.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>Understanding Docker Networks (Easy Concept Explanation)</title>
      <dc:creator>Fahim Ahammed Firoz</dc:creator>
      <pubDate>Sun, 16 Nov 2025 14:27:45 +0000</pubDate>
      <link>https://dev.to/fahimahammed/understanding-docker-networks-easy-concept-explanation-4j9h</link>
      <guid>https://dev.to/fahimahammed/understanding-docker-networks-easy-concept-explanation-4j9h</guid>
      <description>&lt;p&gt;A Docker Network is basically a virtual space where containers can communicate with each other. By default, every Docker container is isolated, meaning it cannot see or talk to any other container. This isolation is good for security, but in real projects we usually run multiple containers together, like a backend API, a frontend, and a database. If these containers cannot talk to each other, nothing will work. That is why Docker Networks exist, they allow containers to communicate safely and easily.&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%2F99mpseu2icvtzkzo5az6.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%2F99mpseu2icvtzkzo5az6.png" alt=" " width="800" height="501"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can think of a Docker Network as a room, and containers as people inside that room. People in the same room can talk to each other freely. People in different rooms cannot communicate unless you create a connection between the rooms. In the same way, containers inside the same Docker Network can communicate smoothly, while containers in different networks remain isolated.&lt;/p&gt;

&lt;p&gt;Docker has different types of networks, but the most commonly used one is the Bridge Network. This network works like a private area where related containers, such as your API and database, stay together and can interact. The Host Network removes the boundary between the container and the machine running it, which makes communication faster but less isolated. The None Network isolates the container completely, giving it no network access at all. The Overlay Network is used in large or multi server environments where containers on different machines need to communicate as if they were in the same room.&lt;/p&gt;

&lt;p&gt;One of the best things about Docker Networks is that containers can talk to each other using their names instead of IP addresses. For example, your API can reach the database simply by using its container name. Docker automatically manages all the underlying network rules, which makes development much easier.&lt;/p&gt;

&lt;p&gt;In simple words, a Docker Network is like Wi Fi for containers. If containers are connected to the same network, they can communicate. If they are not, they stay isolated.&lt;/p&gt;

&lt;p&gt;Docker networking keeps your applications structured, secure, and scalable, and understanding this concept is a big step toward mastering container based development.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>dockernetwork</category>
      <category>development</category>
    </item>
    <item>
      <title>কেন Stripe Date-Based API Versioning ব্যবহার করে? (কেন Traditional Versioning করে না)</title>
      <dc:creator>Fahim Ahammed Firoz</dc:creator>
      <pubDate>Wed, 08 Oct 2025 13:35:16 +0000</pubDate>
      <link>https://dev.to/fahimahammed/ken-stripe-date-based-api-versioning-bybhaar-kre-ken-traditional-versioning-kre-naa-1j9</link>
      <guid>https://dev.to/fahimahammed/ken-stripe-date-based-api-versioning-bybhaar-kre-ken-traditional-versioning-kre-naa-1j9</guid>
      <description>&lt;p&gt;প্রায় সবাই জানি Stripe-এর API অসাধারণ। কিন্তু  জানেন কি কেন তারা traditional /v1, /v2 versioning ব্যবহার না করে, বরং date-based versioning ব্যবহার করে?&lt;/p&gt;

&lt;p&gt;এটা মূলত Stripe-এর developer-friendly এবং stable API design-এর ঝলক।&lt;/p&gt;

&lt;p&gt;Traditional Versioning-এর কিছু সীমাবদ্ধতা রয়েছে। উদাহরণস্বরূপ, যখন একটি API /v1/customers থেকে /v2/customers-এ আপডেট হয়, তখন সাধারণত endpoint structure, data format, এবং response shape-এর বড় পরিবর্তন আসে। এর ফলে existing integrations হঠাৎ ভেঙে যেতে পারে এবং developers-কে নতুন version-এ migrate করতে অনেক সময় ও effort দিতে হয়। এছাড়া, একাধিক version maintain করাও জটিল হয়ে যায়। অর্থাৎ, Traditional Versioning বড় পরিবর্তনের ক্ষেত্রে risk তৈরি করে এবং integration-কে কম stable রাখে।&lt;/p&gt;

&lt;p&gt;Stripe-এর Date-Based Versioning হল এমন একটি পদ্ধতি যেখানে প্রতিটি API version একটি নির্দিষ্ট তারিখের সঙ্গে mark করা থাকে, যেমন 2025-09-30.clover.  এতে করে প্রতিটি major বা monthly release সহজে track করা যায়।&lt;/p&gt;

&lt;p&gt;Major release-এ বড় পরিবর্তন (যা backward-compatible নয়) আনা হয়, কিন্তু monthly release-এ শুধু backward-compatible ছোট পরিবর্তন আসে। এই পদ্ধতিতে, আপনার integration যেই version-এ pinned থাকে, তা নতুন update এলেও ভাঙবে না। Developer রা চাইলে পরবর্তীতে step-by-step নতুন version-এ safely migrate করতে পারেন।&lt;/p&gt;

&lt;p&gt;Stripe internally প্রতিটি request handle করে compatibility layer দিয়ে।&lt;/p&gt;

&lt;p&gt;Main codebase সর্বদা latest থাকে, কিন্তু পুরোনো version-এর জন্য response backward-compatible হয়।&lt;/p&gt;

&lt;p&gt;Stripe-এর SDK যেমন stripe-node, stripe-python, release time-এর API version-এর সাথে pinned থাকে। ফলে Type mismatch বা API inconsistency-এর ঝুঁকি কমে যায়।&lt;/p&gt;

&lt;p&gt;Webhook endpoint তৈরির সময় যেই version নির্বাচন করা হয়, সেই version-এর data format সবসময় ঠিক থাকে। নতুন update আসলেও আপনার webhook break হয় না।&lt;/p&gt;

&lt;p&gt;সহজভাবে- &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Traditional versioning = একবারে big change, risk বেশি&lt;/li&gt;
&lt;li&gt;Date-based versioning = step by step small change, integration always stable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stripe-এ এটি win-win. &lt;/p&gt;

&lt;p&gt;Stripe-এর date-based versioning দেখায় কিভাবে innovation এবং stability একসাথে রাখা যায়। Integration সহজ, upgrades smooth, এবং system সবসময় reliable.&lt;/p&gt;

</description>
      <category>api</category>
      <category>architecture</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Building an AI Chat Rate Limiter with Node.js, Express, and Vercel AI SDK</title>
      <dc:creator>Fahim Ahammed Firoz</dc:creator>
      <pubDate>Sat, 20 Sep 2025 16:04:14 +0000</pubDate>
      <link>https://dev.to/fahimahammed/building-an-ai-chat-rate-limiter-with-nodejs-express-and-vercel-ai-sdk-5240</link>
      <guid>https://dev.to/fahimahammed/building-an-ai-chat-rate-limiter-with-nodejs-express-and-vercel-ai-sdk-5240</guid>
      <description>&lt;p&gt;When building AI chat applications, one of the main challenges is &lt;strong&gt;controlling costs&lt;/strong&gt;. Each AI request has a cost, so you cannot allow unlimited usage. A &lt;strong&gt;rate limiter&lt;/strong&gt; helps solve this by restricting how many requests each user can make in a fixed time period.&lt;/p&gt;

&lt;p&gt;In this article, we will look at how to build a &lt;strong&gt;chatbot backend&lt;/strong&gt; using Node.js, Express, and the Vercel AI SDK. Our system uses a &lt;strong&gt;fixed window rate limiting algorithm&lt;/strong&gt; to manage usage for different user types: Guest, Free, and Premium.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Rate Limiting?
&lt;/h2&gt;

&lt;p&gt;Rate limiting ensures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fair usage for all users&lt;/li&gt;
&lt;li&gt;Protection from abuse&lt;/li&gt;
&lt;li&gt;Cost control for AI services&lt;/li&gt;
&lt;li&gt;Predictable system performance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, if a Guest makes 1,000 requests per hour, your costs can skyrocket. With a limiter, you decide how many requests are allowed.&lt;/p&gt;




&lt;h2&gt;
  
  
  User Types and Limits
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;User Type&lt;/th&gt;
&lt;th&gt;Limit (per hour)&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Guest&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;No login required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;Logged-in users with free plan&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Premium&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;td&gt;Logged-in users with premium plan&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The system identifies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Guests&lt;/strong&gt; by IP address&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logged-in users&lt;/strong&gt; by their &lt;code&gt;user.id&lt;/code&gt; (from JWT token)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  How the Rate Limiter Works
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;A request is sent to &lt;code&gt;/api/chat&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If there is a JWT token, it is verified. If missing, the user is a &lt;strong&gt;Guest&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The system decides the limit based on user type:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Guest = 3&lt;/li&gt;
&lt;li&gt;Free = 10&lt;/li&gt;
&lt;li&gt;Premium = 50&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The request counter is checked for the current &lt;strong&gt;1-hour window&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the user has requests left, the system forwards the query to the AI SDK.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the limit is exceeded, the server returns a &lt;strong&gt;429 error&lt;/strong&gt; with a clear message.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Fixed Window Algorithm
&lt;/h2&gt;

&lt;p&gt;We use a &lt;strong&gt;Fixed Window Algorithm&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep a count of requests per user (or IP).&lt;/li&gt;
&lt;li&gt;If the request is within the same window (1 hour), increase the count.&lt;/li&gt;
&lt;li&gt;If the window has expired, reset the count and start a new window.&lt;/li&gt;
&lt;li&gt;If the count is above the limit, reject the request.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example in memory store:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"user123"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"windowStart"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1695206400000&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means user123 has made 7 requests since the last window started.&lt;/p&gt;




&lt;h2&gt;
  
  
  Flow Diagram
&lt;/h2&gt;

&lt;p&gt;The process can be explained with this flow:&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%2Fkttmol7bu2vj8toi4zxa.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%2Fkttmol7bu2vj8toi4zxa.png" alt="SD" width="800" height="927"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check if the request has a JWT token.&lt;/li&gt;
&lt;li&gt;If valid, assign user type (Free or Premium). Otherwise, assign Guest.&lt;/li&gt;
&lt;li&gt;Apply the rate limit based on user type.&lt;/li&gt;
&lt;li&gt;If the user is new, start tracking requests.&lt;/li&gt;
&lt;li&gt;If the time window has expired, reset the counter.&lt;/li&gt;
&lt;li&gt;If the count is within the limit, allow the request. Otherwise, block it.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;By combining &lt;strong&gt;Express&lt;/strong&gt;, &lt;strong&gt;JWT authentication&lt;/strong&gt;, and the &lt;strong&gt;Vercel AI SDK&lt;/strong&gt;, we built a chatbot backend with &lt;strong&gt;different rate limits for Guests, Free users, and Premium users&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This ensures cost control, fair usage, and a better experience for all users.&lt;/p&gt;

&lt;p&gt;Source code: &lt;a href="https://github.com/fahimahammed/chatbot-throttle" rel="noopener noreferrer"&gt;GitHub - chatbot-throttle&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;⭐ If you find this project useful, don’t forget to star the repository on GitHub!&lt;/p&gt;

</description>
      <category>ratelimit</category>
      <category>fixedwindow</category>
      <category>aisdk</category>
      <category>aichatratelimiter</category>
    </item>
    <item>
      <title>Protect Your API with Token Bucket Rate Limiting</title>
      <dc:creator>Fahim Ahammed Firoz</dc:creator>
      <pubDate>Sat, 20 Sep 2025 06:53:32 +0000</pubDate>
      <link>https://dev.to/fahimahammed/protect-your-api-with-token-bucket-rate-limiting-1g9a</link>
      <guid>https://dev.to/fahimahammed/protect-your-api-with-token-bucket-rate-limiting-1g9a</guid>
      <description>&lt;p&gt;When building APIs, chat services, or real-time systems, one of the biggest challenges is preventing clients from overwhelming your server with too many requests. Without protection, a flood of traffic can slow down performance or even crash the system.&lt;/p&gt;

&lt;p&gt;This is where &lt;strong&gt;rate limiting&lt;/strong&gt; comes in. Among the many techniques available, the &lt;strong&gt;Token Bucket Algorithm&lt;/strong&gt; is widely used because it is simple, efficient, and allows for bursts of traffic without losing overall control.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is Rate Limiting?
&lt;/h2&gt;

&lt;p&gt;Rate limiting is the process of controlling how many requests a client can send to a server in a given period of time.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;A client may be allowed &lt;strong&gt;10 requests per second&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;If they exceed that, their additional requests are rejected until the next second begins.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rate limiting ensures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fair resource usage across users&lt;/li&gt;
&lt;li&gt;Protection against abuse, brute-force attacks, or spam&lt;/li&gt;
&lt;li&gt;Improved server stability and reliability&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Token Bucket Algorithm
&lt;/h2&gt;

&lt;p&gt;The Token Bucket Algorithm works like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each client is assigned a &lt;strong&gt;bucket&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The bucket has a &lt;strong&gt;capacity&lt;/strong&gt; (for example, 10 tokens).&lt;/li&gt;
&lt;li&gt;Tokens are &lt;strong&gt;refilled at a fixed rate&lt;/strong&gt; (for example, 1 token per second).&lt;/li&gt;
&lt;li&gt;Each request &lt;strong&gt;consumes one token&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;If the bucket is empty, the request is &lt;strong&gt;rejected&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach allows &lt;strong&gt;short bursts of requests&lt;/strong&gt; when tokens are available, while still enforcing a long-term average request rate.&lt;/p&gt;




&lt;h2&gt;
  
  
  Token Bucket Flow
&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%2Fx89fgrcauu00ved6bjdy.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%2Fx89fgrcauu00ved6bjdy.png" alt="Token Bucket Rate Limiter SD" width="800" height="904"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The steps are as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Check if the client is new&lt;/strong&gt;&lt;br&gt;
If yes, create a bucket for them with full capacity.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Refill tokens&lt;/strong&gt;&lt;br&gt;
Based on the time elapsed since the last refill.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Check if tokens are available&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;If yes, consume one token and accept the request.&lt;/li&gt;
&lt;li&gt;If no, reject the request.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This balance ensures that clients can make quick bursts of requests but cannot exceed the average allowed rate.&lt;/p&gt;




&lt;h2&gt;
  
  
  Implementing Token Bucket in Node.js
&lt;/h2&gt;

&lt;p&gt;Let’s build a simple HTTP server with Token Bucket Rate Limiting.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Setup
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Configuration&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bucketCapacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// maximum tokens per user&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;refillRate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;        &lt;span class="c1"&gt;// tokens per second&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ipBuckets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// store buckets for each IP&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We define the bucket size, refill rate, and a map to store each user’s token bucket.&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 2: Refill Function
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;refillTokens&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;elapsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastRefillTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// seconds&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;refill&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;elapsed&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;refillRate&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;refill&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bucketCapacity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;refill&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastRefillTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function calculates how many tokens should be added based on the elapsed time since the last refill, and updates the bucket without exceeding its capacity.&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 3: Rate Limiting Middleware
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;rateLimitMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;remoteAddress&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// If user is new, create a bucket&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;ipBuckets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;ipBuckets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bucketCapacity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;lastRefillTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ipBuckets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;refillTokens&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// consume one token&lt;/span&gt;
        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeHead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text/plain&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Request accepted&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeHead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;429&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text/plain&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Too Many Requests&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function manages the bucket for each IP, consumes tokens when available, and rejects requests if tokens are empty.&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 4: Start the Server
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rateLimitMiddleware&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Server running at http://localhost:3000/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This starts the server on port 3000, applying the rate limiting logic to every request.&lt;/p&gt;




&lt;h2&gt;
  
  
  Full Code
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Configuration&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bucketCapacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// maximum tokens per user&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;refillRate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;        &lt;span class="c1"&gt;// tokens per second&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ipBuckets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// store buckets for each IP&lt;/span&gt;

&lt;span class="c1"&gt;// Refill function&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;refillTokens&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;elapsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastRefillTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// seconds&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;refill&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;elapsed&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;refillRate&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;refill&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bucketCapacity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;refill&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastRefillTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Middleware&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;rateLimitMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;remoteAddress&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// If user is new, create a bucket&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;ipBuckets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;ipBuckets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bucketCapacity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;lastRefillTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ipBuckets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;refillTokens&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// consume one token&lt;/span&gt;
        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeHead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text/plain&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Request accepted&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeHead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;429&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text/plain&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Too Many Requests&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Start server&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rateLimitMiddleware&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Server running at http://localhost:3000/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Use Cases
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;API Gateways&lt;/strong&gt;: prevent abuse by limiting requests per client&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chat Applications&lt;/strong&gt;: stop spamming by controlling message frequency&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authentication Systems&lt;/strong&gt;: slow down brute-force login attempts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IoT Devices&lt;/strong&gt;: manage bursts of data from sensors and devices&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Benefits of Token Bucket
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Allows bursts of requests up to the bucket capacity&lt;/li&gt;
&lt;li&gt;Maintains a steady long-term request rate&lt;/li&gt;
&lt;li&gt;Simple and efficient implementation&lt;/li&gt;
&lt;li&gt;Predictable refill behavior&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The Token Bucket Algorithm is a practical and effective way to implement rate limiting. It combines flexibility and control by allowing temporary bursts while maintaining a predictable average request rate.&lt;/p&gt;

&lt;p&gt;If you are building APIs, chat systems, or real-time applications, Token Bucket rate limiting can help you protect your server, ensure fairness, and improve system reliability.&lt;/p&gt;

</description>
      <category>ratelimiting</category>
      <category>tokenbucket</category>
      <category>api</category>
      <category>backend</category>
    </item>
    <item>
      <title>TypedSQL in Prisma: Type-Safe SQL Made Simple</title>
      <dc:creator>Fahim Ahammed Firoz</dc:creator>
      <pubDate>Fri, 30 Aug 2024 09:35:06 +0000</pubDate>
      <link>https://dev.to/fahimahammed/typedsql-in-prisma-type-safe-sql-made-simple-1n5e</link>
      <guid>https://dev.to/fahimahammed/typedsql-in-prisma-type-safe-sql-made-simple-1n5e</guid>
      <description>&lt;p&gt;TypedSQL is a powerful feature in Prisma that allows developers to write raw SQL queries while maintaining type safety and full integration with Prisma’s TypeScript client. This feature is especially useful for scenarios where complex SQL queries are necessary, but you still want to benefit from Prisma’s type safety, code generation, and developer experience (DX). In this blog, we'll walk through the steps to get started with TypedSQL, how to pass arguments to queries, define argument types, and some best practices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up TypedSQL in Prisma
&lt;/h2&gt;

&lt;p&gt;To start using TypedSQL in your Prisma project, follow these steps:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Install the Required Packages
&lt;/h3&gt;

&lt;p&gt;Ensure that you have &lt;code&gt;@prisma/client&lt;/code&gt; and &lt;code&gt;prisma&lt;/code&gt; installed and updated to at least version 5.19.0. You can do this by running the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @prisma/client@latest
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-D&lt;/span&gt; prisma@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Enable TypedSQL in Your Schema
&lt;/h3&gt;

&lt;p&gt;Add the &lt;code&gt;typedSql&lt;/code&gt; preview feature flag to your &lt;code&gt;schema.prisma&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;generator client {
  provider = "prisma-client-js"
  previewFeatures = ["typedSql"]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Create a Directory for SQL Files
&lt;/h3&gt;

&lt;p&gt;Inside your &lt;code&gt;prisma&lt;/code&gt; directory, create a &lt;code&gt;sql&lt;/code&gt; directory where you'll write your SQL queries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; prisma/sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Write Your SQL Queries
&lt;/h3&gt;

&lt;p&gt;Create a new &lt;code&gt;.sql&lt;/code&gt; file in the &lt;code&gt;prisma/sql&lt;/code&gt; directory. The file name must be a valid JavaScript identifier and cannot start with a &lt;code&gt;$&lt;/code&gt;. For example, let's create a &lt;code&gt;getUsersWithPosts.sql&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- prisma/sql/getUsersWithPosts.sql&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;"postCount"&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="nv"&gt;"User"&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;
&lt;span class="k"&gt;LEFT&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="nv"&gt;"Post"&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;"authorId"&lt;/span&gt;
&lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Generate the Prisma Client
&lt;/h3&gt;

&lt;p&gt;To generate TypeScript functions and types for your SQL queries, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;prisma generate &lt;span class="nt"&gt;--sql&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want Prisma to regenerate the client automatically after every change, you can use the &lt;code&gt;--watch&lt;/code&gt; flag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;prisma generate &lt;span class="nt"&gt;--sql&lt;/span&gt; &lt;span class="nt"&gt;--watch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. Use TypedSQL Queries in Your Code
&lt;/h3&gt;

&lt;p&gt;You can now import and use your SQL queries in your TypeScript code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PrismaClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@prisma/client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getUsersWithPosts&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@prisma/client/sql&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PrismaClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;usersWithPostCounts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;$queryRawTyped&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getUsersWithPosts&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;usersWithPostCounts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Passing Arguments to TypedSQL Queries
&lt;/h2&gt;

&lt;p&gt;To pass arguments to your TypedSQL queries, you can use parameterized queries. This allows you to write flexible and reusable SQL statements while maintaining type safety.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example: Passing Parameters
&lt;/h3&gt;

&lt;p&gt;In your SQL file, use placeholders for the parameters you want to pass. The syntax for placeholders depends on your database engine. For PostgreSQL, use the positional placeholders &lt;code&gt;$1&lt;/code&gt;, &lt;code&gt;$2&lt;/code&gt;, etc.:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- prisma/sql/getUsersByAge.sql&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When using the generated function in your TypeScript code, pass the arguments as additional parameters to &lt;code&gt;$queryRawTyped&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PrismaClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@prisma/client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getUsersByAge&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@prisma/client/sql&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PrismaClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;minAge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;maxAge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;$queryRawTyped&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getUsersByAge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;minAge&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;maxAge&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example: Passing Array Arguments
&lt;/h3&gt;

&lt;p&gt;TypedSQL supports passing arrays as arguments for PostgreSQL. Use PostgreSQL's &lt;code&gt;ANY&lt;/code&gt; operator with an array parameter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- prisma/sql/getUsersByIds.sql&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;ANY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In your TypeScript code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PrismaClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@prisma/client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getUsersByIds&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@prisma/client/sql&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PrismaClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userIds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;prisma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;$queryRawTyped&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getUsersByIds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userIds&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Defining Argument Types in SQL Files
&lt;/h2&gt;

&lt;p&gt;You can define the types of arguments directly in your SQL files using specific comments. This enhances type safety and ensures that the TypeScript client is fully aware of the types being passed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example: Typing Arguments
&lt;/h3&gt;

&lt;p&gt;Add the following comments to define the types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- @param {Int} $1:minAge The minimum age of the user&lt;/span&gt;
&lt;span class="c1"&gt;-- @param {Int} $2:maxAge The maximum age of the user&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The format is consistent across all supported database engines and ensures that your TypeScript code accurately reflects the SQL query structure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pros and Cons of Using TypedSQL
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Pros
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Type Safety&lt;/strong&gt;: TypedSQL provides strong type safety for raw SQL queries, reducing the risk of runtime errors and ensuring consistent data handling.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Integrated DX&lt;/strong&gt;: By integrating with Prisma, TypedSQL allows you to write complex SQL queries while still benefiting from Prisma’s developer tools, like autocomplete and type inference.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reusable Queries&lt;/strong&gt;: TypedSQL encourages the reuse of SQL queries across your application, making it easier to maintain and update your codebase.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Protection Against SQL Injection&lt;/strong&gt;: By using parameterized queries, TypedSQL helps protect your application against SQL injection attacks, which are a common security vulnerability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Better Performance for Complex Queries&lt;/strong&gt;: TypedSQL allows you to execute more complex and efficient SQL queries directly within Prisma, bypassing some of the limitations of Prisma’s query builder.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Cons
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Limited Dynamic SQL Support&lt;/strong&gt;: TypedSQL does not natively support constructing SQL queries with dynamically added columns. For such cases, you need to fall back to &lt;code&gt;$queryRaw&lt;/code&gt; or &lt;code&gt;$executeRaw&lt;/code&gt;, which means losing type safety.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Increased Complexity&lt;/strong&gt;: Using raw SQL, even with type safety, adds a layer of complexity to your codebase, especially if your team is more familiar with Prisma’s query builder syntax.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Learning Curve&lt;/strong&gt;: Developers need to be comfortable with both SQL and Prisma’s TypeScript client to use TypedSQL effectively. This might require additional learning for some team members.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dependency on Preview Features&lt;/strong&gt;: TypedSQL is currently a preview feature, meaning it’s not yet fully stable and might undergo breaking changes in future releases.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lack of Full ORM Benefits&lt;/strong&gt;: When using TypedSQL, you miss out on some of the abstractions and conveniences that Prisma’s ORM provides, such as automatic relation handling and query optimization.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;TypedSQL is a powerful tool in Prisma’s ecosystem that bridges the gap between raw SQL and type-safe query construction. It offers the flexibility of raw SQL with the benefits of Prisma’s TypeScript client, making it ideal for scenarios where you need fine-grained control over your database queries.&lt;/p&gt;

&lt;p&gt;However, it’s important to weigh the pros and cons before adopting TypedSQL in your project. While it offers many advantages, particularly in terms of type safety and query performance, it also introduces complexity and requires a good understanding of SQL.&lt;/p&gt;

&lt;p&gt;By following the steps outlined in this guide, you can start using TypedSQL in your Prisma projects, writing more complex queries while maintaining the benefits of Prisma’s type-safe client.&lt;/p&gt;

</description>
      <category>typedsql</category>
      <category>prisma</category>
      <category>typesafe</category>
      <category>sql</category>
    </item>
    <item>
      <title>🚀3 Important Rules for Naming Variables in Excellent Code</title>
      <dc:creator>Fahim Ahammed Firoz</dc:creator>
      <pubDate>Sun, 17 Mar 2024 20:38:03 +0000</pubDate>
      <link>https://dev.to/fahimahammed/3-important-rules-for-naming-variables-in-excellent-code-f18</link>
      <guid>https://dev.to/fahimahammed/3-important-rules-for-naming-variables-in-excellent-code-f18</guid>
      <description>&lt;p&gt;Good variable names are just as important as clear function names for making code easy to understand. Here are 3 simple rules to make your variable names better:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Meaningful Names:&lt;/strong&gt; Replace generic names (like temp or x, y, x) with names that reflect their purpose.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;❌ tempData&lt;br&gt;&lt;br&gt;
✅ customerOrder&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Descriptive Naming:&lt;/strong&gt; Use descriptive terms that explain the content of the variable.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;❌ isSomething (unclear what "something" is)&lt;br&gt;
✅ isUserLoggedIn (clear and concise)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Case Consistency&lt;/strong&gt;: Pick a case convention (snake_case, camelCase) and stick to it throughout your codebase.&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Snake Case&lt;/strong&gt;: Lowercase letters with underscores for separation (e.g., total_price)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Camel Case&lt;/strong&gt;: Lowercase with the first letter of each word capitalized (e.g., totalPrice)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Bonus Tip:&lt;/strong&gt;  Consider adding prefixes or suffixes for specific variable types (e.g., strFirstName, intEmployeeID).&lt;/p&gt;

&lt;p&gt;By following these principles, your variables become self-documenting, improving code readability and maintainability for yourself and your fellow developers.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Consistent naming across functions and variables is key!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>coding</category>
      <category>variable</category>
      <category>cleancode</category>
      <category>variablenaming</category>
    </item>
    <item>
      <title>GraphQL vs tRPC: Picking the Best Fit for Your Project</title>
      <dc:creator>Fahim Ahammed Firoz</dc:creator>
      <pubDate>Sat, 28 Oct 2023 19:33:21 +0000</pubDate>
      <link>https://dev.to/fahimahammed/graphql-vs-trpc-picking-the-best-fit-for-your-project-4b97</link>
      <guid>https://dev.to/fahimahammed/graphql-vs-trpc-picking-the-best-fit-for-your-project-4b97</guid>
      <description>&lt;p&gt;&lt;strong&gt;GraphQL *&lt;em&gt;এর সাথে বর্তমান সময়ে **tRPC *&lt;/em&gt;নামে একটি টেকনোলজির নাম বেশি শোনা যাচ্ছে।  এটি একটি **remote procedure call (RPC) framework&lt;/strong&gt; যা বিশেষভাবে TypeScript এর জন্য ডিজাইন করা হয়েছে। এটিতে ক্লায়েন্ট সাইট থেকেই সার্ভার ডিফাইন ফাংশন কল করা যায়। tRPC বেশ first এবং তুলনামূলক ব্যবহার করা সহজ। এছাড়াও এর এমন কিছু features রয়েছে যার জন্য এটিকে &lt;strong&gt;microservices-based applications&lt;/strong&gt; তৈরির জন্য আদর্শ বলা যেতে পারে। &lt;/p&gt;

&lt;p&gt;&lt;em&gt;কি!! এই কথাটুকু শুনে graphql শেখা বাদ দিয়ে tRPC শিখবেন? নাকি কনফিউশনে পড়ে গেলেন কোনটি শেখা ভালো হবে? আবার এমনটিও মনে হতে পারে যে পুরান পাগলে ভাত পায় না নতুন পাগলের আমদানি।&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;তাহলে আগে এই পাগল দ্বয়ের উদয় হলো কোন সময়ে সেটি জানার চেষ্টা করি। ২০১২ সালে মার্ক সাইমন, জোসেফ উইলিয়ামস এবং জোয়েল ওয়াল্টন GraphQL তৈরি করেছিল এবং ২০১৫ সালে এটির প্রথম ভার্সন রিলিজ করা হয়েছিল। ২০১৬ সাল থেকে এটি বেশ জনপ্রিয় হতে থাকে এবং facebook, Google, Microsoft এর মতো বড় বড় কোম্পানি এটি ব্যবহার করা শুরু করে। &lt;/p&gt;

&lt;p&gt;অন্যদিকে, ২০২০ সালে ডেভিড ক্রাউন tRPC নামে একটি RPC framework তৈরি করে এবং ২০২১ সালে tRPC 1.0 রিলিজ করা হয়েছিল। ২০২২ সাল থেকে এটি বেশ জনপ্রিয় হতে শুরু করে। &lt;/p&gt;

&lt;p&gt;_GraphQL এবং tRPC দুটিই API তৈরির জন্য ব্যবহৃত টেকনোলজি। তবে এদের মধ্যে কিছু গুরুত্বপূর্ণ পার্থক্য রয়েছে। যেমনঃ _&lt;br&gt;
GraphQL একটি query language, &amp;amp; tRPC একটি RPC Framework. এর মানে হল যে GraphQL ব্যবহার করে, আপনি একটি API তৈরি করতে পারেন যা ক্লায়েন্টকে সার্ভার থেকে data access করতে দেয়। অন্যদিকে, tRPC ব্যবহার করে, আপনি একটি API তৈরি করতে পারেন যা ক্লায়েন্ট এবং সার্ভার মধ্যে data transfer করতে দেয়। পার্ফমেন্সের দিক থেকে tRPC কিছুটা এগিয়ে থাকলেও GraphQL flexibility এর দিক থেকে এগিয়ে রয়েছে। GraphQL API তৈরিতে বিভিন্ন ধরনের ল্যাগুয়েজ ব্যবহার করা যায়, কিন্তু tRPC শুধু মাত্র TypeScript এর জন্য ডিজাইন করা। &lt;/p&gt;

&lt;p&gt;দুটিই বেশ ভালো টেকনোলজি এবং দুটিরই ভালো সুবিধা রয়েছে আবার কিছু লিমিটেশনও রয়েছে। তাহলে কোন ধরনের প্রজেক্টে কোনটি use করা উচিত? &lt;/p&gt;

&lt;p&gt;আপনি যদি একটি powerful &amp;amp; flexible API তৈরি করতে চান যার মাধ্যমে ক্লায়েন্ট থেকে স্পেসিফিক ডেটার জন্য রিকোয়েস্ট করতে পারবেন তাহলে GraphQL ভালো পছন্দ হতে পারে। যেমনঃ Social Media API, Content Management System (CMS), Data Analytics API. &lt;/p&gt;

&lt;p&gt;আবার অন্যদিকে, আপনি যদি simple &amp;amp; ব্যবহার করা সহজ এমন API  তৈরি করতে চান যা data transfer করতে পারবে, তাহলে tRPC ভালো পছন্দ হতে পারে। tRPC মূলত microservice based application এর জন্য ডিজাইন করা হয়েছে। এছাড়াও real-time chat application, gaming application তৈরিতেও এটি ব্যবহার করা যেতে পারে। &lt;/p&gt;

&lt;p&gt;সবশেষে বলতে পারি যে, GraphQL এবং tRPC উভয়ই শক্তিশালী এবং কার্যকর টেকনোলজি। দুটিরই বেশ জনপ্রিয়তা এবং প্রয়োজনীয়তা রয়েছে। এখন আপনার কাজের ধরন এবং প্রয়োজনীয়তার উপর নির্ভর করছে আপনি আপনার প্রজেক্টে/এপ্লিকেশনে কোনটি ব্যবহার করবেন।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;_References: _&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.logrocket.com/trpc-vs-graphql-better-projects/" rel="noopener noreferrer"&gt;https://blog.logrocket.com/trpc-vs-graphql-better-projects/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://graphql.org/" rel="noopener noreferrer"&gt;https://graphql.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://trpc.io/" rel="noopener noreferrer"&gt;https://trpc.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cleancommit.io/blog/trpc-vs-graphql-how-to-choose-the-best-option-for-your-next-project/" rel="noopener noreferrer"&gt;https://cleancommit.io/blog/trpc-vs-graphql-how-to-choose-the-best-option-for-your-next-project/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>graphql</category>
      <category>trpc</category>
      <category>api</category>
    </item>
  </channel>
</rss>
