<?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: Neel Patel</title>
    <description>The latest articles on DEV Community by Neel Patel (@neelp03).</description>
    <link>https://dev.to/neelp03</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F899030%2F46d7cad1-06bb-44ac-90d0-26e2d5f310f4.jpg</url>
      <title>DEV Community: Neel Patel</title>
      <link>https://dev.to/neelp03</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/neelp03"/>
    <language>en</language>
    <item>
      <title>Tailscale + Raspberry Pi: HomeLab Gateway</title>
      <dc:creator>Neel Patel</dc:creator>
      <pubDate>Wed, 10 Dec 2025 05:35:39 +0000</pubDate>
      <link>https://dev.to/neelp03/tailscale-raspberry-pi-homelab-gateway-4fin</link>
      <guid>https://dev.to/neelp03/tailscale-raspberry-pi-homelab-gateway-4fin</guid>
      <description>&lt;h2&gt;
  
  
  Build Your Own HomeLab Gateway: Tailscale + Raspberry Pi
&lt;/h2&gt;

&lt;p&gt;Your home network is a goldmine of services—Pi-hole blocking ads, Home Assistant controlling your lights, Jellyfin streaming your media library. But the moment you step outside your front door, it all vanishes behind your router's firewall.&lt;/p&gt;

&lt;p&gt;What if you could access everything securely from anywhere, without exposing a single port to the internet?&lt;/p&gt;

&lt;p&gt;Enter &lt;strong&gt;Tailscale on a Raspberry Pi&lt;/strong&gt;—your personal gateway to a self-hosted, privacy-first HomeLab that follows you everywhere.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Combo Works So Well
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Raspberry Pi Advantage
&lt;/h3&gt;

&lt;p&gt;The Raspberry Pi 5 is the perfect HomeLab foundation:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Spec&lt;/th&gt;
&lt;th&gt;Why It Matters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Quad-core Cortex-A76 @ 2.4GHz&lt;/td&gt;
&lt;td&gt;Handles multiple containers without breaking a sweat&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Up to 16GB RAM&lt;/td&gt;
&lt;td&gt;Room for Ollama, databases, and more&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PCIe 2.0 support&lt;/td&gt;
&lt;td&gt;Attach NVMe SSDs for real storage performance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gigabit Ethernet&lt;/td&gt;
&lt;td&gt;Full-speed network throughput&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4-5W idle power&lt;/td&gt;
&lt;td&gt;Runs 24/7 for pennies per month&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  The Tailscale Magic
&lt;/h3&gt;

&lt;p&gt;Tailscale is a mesh VPN built on WireGuard that eliminates the nightmare of traditional VPN setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero port forwarding&lt;/strong&gt; — Works behind NAT, firewalls, even carrier-grade NAT&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero configuration&lt;/strong&gt; — No IP addresses to memorize, no certificates to manage&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Device-to-device encryption&lt;/strong&gt; — Traffic never touches Tailscale's servers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free tier&lt;/strong&gt; — Connect up to 100 devices (more than enough for most HomeLabs)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Together, they create a secure tunnel to your entire home infrastructure from any device, anywhere in the world.&lt;/p&gt;




&lt;h2&gt;
  
  
  The HomeLab Stack
&lt;/h2&gt;

&lt;p&gt;Here's what we're building—a complete self-hosted ecosystem accessible from anywhere:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────────────────┐
│                   Your Phone/Laptop                  │
│                  (Tailscale Client)                  │
└──────────────────────────┬──────────────────────────┘
                           │ Encrypted Tunnel
                           ▼
┌─────────────────────────────────────────────────────┐
│              Raspberry Pi 5 (Gateway)                │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐  │
│  │   Pi-hole   │  │  Portainer  │  │  Tailscale  │  │
│  │  (Ad Block) │  │ (Container) │  │ (Subnet     │  │
│  │             │  │             │  │  Router)    │  │
│  └─────────────┘  └─────────────┘  └─────────────┘  │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐  │
│  │    Home     │  │   Ollama    │  │   Uptime    │  │
│  │  Assistant  │  │  (Local AI) │  │    Kuma     │  │
│  └─────────────┘  └─────────────┘  └─────────────┘  │
└─────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Setting Up Tailscale on Your Pi
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Raspberry Pi (3, 4, or 5) running Raspberry Pi OS&lt;/li&gt;
&lt;li&gt;Stable internet connection (Ethernet recommended)&lt;/li&gt;
&lt;li&gt;A free &lt;a href="https://tailscale.com/" rel="noopener noreferrer"&gt;Tailscale account&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;

&lt;p&gt;SSH into your Pi and run:&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;# Update your system&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt upgrade &lt;span class="nt"&gt;-y&lt;/span&gt;

&lt;span class="c"&gt;# Install Tailscale with one command&lt;/span&gt;
curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://tailscale.com/install.sh | sh

&lt;span class="c"&gt;# Start Tailscale&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;tailscale up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll get a URL to authenticate in your browser. Log in with Google, GitHub, or Microsoft, and your Pi joins your private network instantly.&lt;/p&gt;

&lt;p&gt;Verify it's working:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tailscale status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see your Pi listed with a &lt;code&gt;100.x.x.x&lt;/code&gt; Tailscale IP address.&lt;/p&gt;




&lt;h2&gt;
  
  
  Configuring the Gateway Features
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Enable Subnet Router (Access Your Whole Network)
&lt;/h3&gt;

&lt;p&gt;This lets you reach every device on your home network through Tailscale—not just the Pi:&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;# Enable IP forwarding&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'net.ipv4.ip_forward = 1'&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; /etc/sysctl.conf
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'net.ipv6.conf.all.forwarding = 1'&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; /etc/sysctl.conf
&lt;span class="nb"&gt;sudo &lt;/span&gt;sysctl &lt;span class="nt"&gt;-p&lt;/span&gt;

&lt;span class="c"&gt;# Advertise your local subnet (adjust for your network)&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;tailscale up &lt;span class="nt"&gt;--advertise-routes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;192.168.1.0/24
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then approve the route in the &lt;a href="https://login.tailscale.com/admin/machines" rel="noopener noreferrer"&gt;Tailscale admin console&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Find your Pi in the Machines list&lt;/li&gt;
&lt;li&gt;Click the &lt;code&gt;...&lt;/code&gt; menu → &lt;strong&gt;Edit route settings&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Enable your advertised subnet&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now any Tailscale device can reach &lt;code&gt;192.168.1.x&lt;/code&gt; addresses directly.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Enable Exit Node (Route All Traffic Through Home)
&lt;/h3&gt;

&lt;p&gt;Want to browse the web from a coffee shop as if you're at home? Make your Pi an exit node:&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;sudo &lt;/span&gt;tailscale up &lt;span class="nt"&gt;--advertise-routes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;192.168.1.0/24 &lt;span class="nt"&gt;--advertise-exit-node&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Approve the exit node in the admin console the same way you approved routes.&lt;/p&gt;

&lt;p&gt;On your phone or laptop, select your Pi as the exit node in Tailscale settings. All your traffic now flows through your home connection.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Disable Key Expiry (Set It and Forget It)
&lt;/h3&gt;

&lt;p&gt;By default, Tailscale keys expire after 180 days. For a headless HomeLab server, disable this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="https://login.tailscale.com/admin/machines" rel="noopener noreferrer"&gt;Tailscale admin console&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Find your Pi → click &lt;code&gt;...&lt;/code&gt; → &lt;strong&gt;Disable key expiry&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Your Pi stays connected permanently without re-authentication.&lt;/p&gt;




&lt;h2&gt;
  
  
  Building the HomeLab Services
&lt;/h2&gt;

&lt;p&gt;With Tailscale running, let's add the services that make a HomeLab useful.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pi-hole: Network-Wide Ad Blocking
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sSL&lt;/span&gt; https://install.pi-hole.net | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Configure your router to use the Pi's IP as its DNS server, or set Tailscale's DNS settings to use your Pi-hole. Ads disappear across all your devices—even remotely.&lt;/p&gt;

&lt;h3&gt;
  
  
  Portainer: Container Management Made Visual
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install Docker&lt;/span&gt;
curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://get.docker.com | sh
&lt;span class="nb"&gt;sudo &lt;/span&gt;usermod &lt;span class="nt"&gt;-aG&lt;/span&gt; docker &lt;span class="nv"&gt;$USER&lt;/span&gt;

&lt;span class="c"&gt;# Install Portainer&lt;/span&gt;
docker volume create portainer_data
docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 9443:9443 &lt;span class="nt"&gt;--name&lt;/span&gt; portainer &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;always &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; /var/run/docker.sock:/var/run/docker.sock &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; portainer_data:/data &lt;span class="se"&gt;\&lt;/span&gt;
  portainer/portainer-ce:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Access Portainer at &lt;code&gt;https://[your-pi-tailscale-ip]:9443&lt;/code&gt; from anywhere.&lt;/p&gt;

&lt;h3&gt;
  
  
  Home Assistant: Smart Home Control
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; homeassistant &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;unless-stopped &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; /home/pi/homeassistant:/config &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; /etc/localtime:/etc/localtime:ro &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--network&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;host &lt;span class="se"&gt;\&lt;/span&gt;
  ghcr.io/home-assistant/home-assistant:stable
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Control your lights, thermostat, and automations from anywhere in the world.&lt;/p&gt;

&lt;h3&gt;
  
  
  Uptime Kuma: Service Monitoring
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; uptime-kuma &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;always &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 3001:3001 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; uptime-kuma:/app/data &lt;span class="se"&gt;\&lt;/span&gt;
  louislam/uptime-kuma:1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Get alerts when any of your self-hosted services go down.&lt;/p&gt;




&lt;h2&gt;
  
  
  Real-World Use Cases
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Working From Anywhere
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;SSH into your home development server&lt;/li&gt;
&lt;li&gt;Access your NAS files as if you're on the couch&lt;/li&gt;
&lt;li&gt;Print to your home printer from a hotel room&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Travel Security
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use your home connection as an exit node on sketchy hotel WiFi&lt;/li&gt;
&lt;li&gt;Pi-hole blocks ads even when you're abroad&lt;/li&gt;
&lt;li&gt;Access geo-restricted content from "home"&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Family Tech Support
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Mail a Pi to your parents' house&lt;/li&gt;
&lt;li&gt;Join their network remotely to fix issues&lt;/li&gt;
&lt;li&gt;Set up Pi-hole to protect them from malicious ads&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Self-Hosted Everything
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Jellyfin for media streaming without Plex's cloud dependency&lt;/li&gt;
&lt;li&gt;Vaultwarden for self-hosted password management&lt;/li&gt;
&lt;li&gt;Nextcloud for your own private cloud storage&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Security Considerations
&lt;/h2&gt;

&lt;p&gt;This setup is inherently secure, but here are additional hardening steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Keep everything updated&lt;/strong&gt;: &lt;code&gt;sudo apt update &amp;amp;&amp;amp; sudo apt upgrade -y&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Tailscale ACLs&lt;/strong&gt;: Restrict which devices can access which services&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enable MFA&lt;/strong&gt; on your Tailscale account&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitor access&lt;/strong&gt; via Uptime Kuma and Tailscale's audit logs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Disable password SSH&lt;/strong&gt;: Use Tailscale SSH or key-based auth only&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;For under $100 in hardware and $0/month in software costs, you get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A secure VPN that works everywhere&lt;/li&gt;
&lt;li&gt;Network-wide ad blocking&lt;/li&gt;
&lt;li&gt;Complete smart home control&lt;/li&gt;
&lt;li&gt;Your own private AI server&lt;/li&gt;
&lt;li&gt;Service monitoring and alerts&lt;/li&gt;
&lt;li&gt;Access to every device on your home network&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All running on a device that sips 5 watts of power.&lt;/p&gt;

&lt;p&gt;The best part? Once it's set up, it just works. No subscriptions. No cloud dependencies. No data leaving your control.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your home network, everywhere you go.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://tailscale.com/download/linux/rpi" rel="noopener noreferrer"&gt;Official Tailscale Download for Raspberry Pi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tailscale.com/kb/1114/pi-hole" rel="noopener noreferrer"&gt;Tailscale Pi-hole Integration Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.freecodecamp.org/news/set-up-a-home-vpn-using-tailscale-on-a-raspberry-pi/" rel="noopener noreferrer"&gt;FreeCodeCamp Home VPN Tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pimylifeup.com/raspberry-pi-tailscale/" rel="noopener noreferrer"&gt;Pi My Life Up Tailscale Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/johnnyfivepi/tailscale-on-raspberry-pi" rel="noopener noreferrer"&gt;GitHub Exit Node Setup Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>raspberrypi</category>
      <category>tailscale</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Rebuilding EnviroX: Overcoming Early Flaws to Automate Development Environments</title>
      <dc:creator>Neel Patel</dc:creator>
      <pubDate>Sun, 27 Oct 2024 20:11:06 +0000</pubDate>
      <link>https://dev.to/neelp03/rebuilding-envirox-overcoming-early-flaws-to-automate-development-environments-12ld</link>
      <guid>https://dev.to/neelp03/rebuilding-envirox-overcoming-early-flaws-to-automate-development-environments-12ld</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;em&gt;Automate your development environment setup with ease.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Setting up a development environment can often be a tedious and error-prone process, especially when working with multiple programming languages and frameworks. To address this challenge, I embarked on creating &lt;strong&gt;EnviroX&lt;/strong&gt;, a CLI tool designed to automate the setup of development environments for various languages like Node.js, Python, and Go.&lt;/p&gt;

&lt;p&gt;In this article, I'll walk you through the journey of EnviroX, starting from its initial flawed version (0.1.1) to its current robust state. We'll explore the challenges faced, the solutions implemented, and the capabilities that make EnviroX a valuable tool for developers.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;The Flaws in the Original Version (0.1.1)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;When I first developed EnviroX version 0.1.1, my goal was to create a simple tool that could detect the project's language and install the necessary dependencies automatically. However, the initial version had several significant flaws that hindered its effectiveness:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Limited Functionality&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Node.js Only:&lt;/strong&gt; The tool only checked if Node.js was installed and did not handle other languages or frameworks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No Dependency Installation:&lt;/strong&gt; It didn't install project dependencies from &lt;code&gt;package.json&lt;/code&gt; or other configuration files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lack of Automation:&lt;/strong&gt; The promise of automating environment setup was unfulfilled due to incomplete implementation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. Memory Leak Problems&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Improper Async Handling:&lt;/strong&gt; Inconsistent use of asynchronous functions led to unhandled promises and potential memory leaks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource Management:&lt;/strong&gt; There was a lack of proper error handling and resource cleanup, which could cause the tool to consume unnecessary system resources.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. Inconsistent Code Structure&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Redundant Functions:&lt;/strong&gt; Duplicate code across different modules made maintenance difficult.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Poor Error Handling:&lt;/strong&gt; Errors were not adequately caught or reported, leading to silent failures.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inadequate OS Support:&lt;/strong&gt; Limited detection of operating systems resulted in compatibility issues, especially on Windows.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;4. User Experience Issues&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Minimal Feedback:&lt;/strong&gt; The tool provided little to no feedback during execution, leaving users unsure of what was happening.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lack of Documentation:&lt;/strong&gt; Insufficient instructions and help options made it challenging for users to understand how to use the tool.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;The Path to Improvement&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Recognizing these flaws, I set out to overhaul EnviroX, focusing on creating a more robust, user-friendly, and functional tool. Here's how I addressed the issues:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Expanding Functionality&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Language Support:&lt;/strong&gt; Implemented detection and setup for Python and Go projects by identifying &lt;code&gt;requirements.txt&lt;/code&gt; and &lt;code&gt;go.mod&lt;/code&gt; files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dependency Installation:&lt;/strong&gt; Added automatic installation of dependencies using appropriate package managers (&lt;code&gt;npm&lt;/code&gt;, &lt;code&gt;pip&lt;/code&gt;, &lt;code&gt;go mod&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatic Detection:&lt;/strong&gt; Enhanced the tool to automatically detect the project type based on configuration files and set up the environment accordingly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. Fixing Memory Leaks and Async Issues&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Consistent Async/Await Usage:&lt;/strong&gt; Updated all asynchronous functions to use &lt;code&gt;async/await&lt;/code&gt;, ensuring proper execution flow and error handling.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Promise Handling:&lt;/strong&gt; Ensured that all promises are properly resolved or rejected, preventing unhandled promise rejections.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource Cleanup:&lt;/strong&gt; Implemented proper resource management to prevent memory leaks.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. Improving Code Structure&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Modular Design:&lt;/strong&gt; Refactored code into separate modules (&lt;code&gt;installTools.js&lt;/code&gt;, &lt;code&gt;envSetup.js&lt;/code&gt;) for better maintainability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error Handling:&lt;/strong&gt; Added comprehensive try-catch blocks and error messages to assist in debugging and user feedback.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced OS Detection:&lt;/strong&gt; Improved operating system detection to support Linux, macOS, and Windows, adjusting commands accordingly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;4. Enhancing User Experience&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;User Feedback with Spinners:&lt;/strong&gt; Integrated &lt;code&gt;ora&lt;/code&gt; spinners and &lt;code&gt;chalk&lt;/code&gt; for colored console output, providing real-time feedback.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Help and Documentation:&lt;/strong&gt; Added a &lt;code&gt;--help&lt;/code&gt; option and updated the README with detailed instructions and examples.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Continued Execution After Errors:&lt;/strong&gt; Modified the tool to continue setting up other environments even if one fails, ensuring maximum utility.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Capabilities of EnviroX&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;EnviroX has evolved into a powerful tool that automates the setup of development environments with ease. Here's what it offers:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Supported Languages and Tools&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Node.js&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Detects &lt;code&gt;package.json&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Installs dependencies using &lt;code&gt;npm&lt;/code&gt; or &lt;code&gt;yarn&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Python&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Detects &lt;code&gt;requirements.txt&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Installs dependencies using &lt;code&gt;pip&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Go&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Detects &lt;code&gt;go.mod&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Sets up the Go environment using &lt;code&gt;go mod&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Docker&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;(Coming soon)&lt;/em&gt; Detects &lt;code&gt;Dockerfile&lt;/code&gt; and builds Docker images.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Key Features&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Automatic Detection and Setup&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;envirox&lt;/code&gt; in your project directory, and it will detect and set up the environment automatically.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Language-Specific Setup&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;--language=&amp;lt;language&amp;gt;&lt;/code&gt; to set up a specific environment.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Cross-Platform Compatibility&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Works on Linux, macOS, and Windows systems.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Robust Error Handling&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Continues with other setups even if one fails.&lt;/li&gt;
&lt;li&gt;Provides clear error messages for troubleshooting.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;User-Friendly CLI&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Clear and informative console output.&lt;/li&gt;
&lt;li&gt;Helpful options like &lt;code&gt;--help&lt;/code&gt; for guidance.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Installation&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://nodejs.org/" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt; (version 14 or higher)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Install via npm&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;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; envirox
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Usage&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Automatic Detection and Setup&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;envirox
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Specific Language Setup&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;envirox &lt;span class="nt"&gt;--language&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;node
envirox &lt;span class="nt"&gt;--language&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;python
envirox &lt;span class="nt"&gt;--language&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Help&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;envirox &lt;span class="nt"&gt;--help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  &lt;strong&gt;The Development Journey&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Addressing Windows Compatibility Issues&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;One of the challenges was ensuring EnviroX worked seamlessly on Windows systems. Specifically, the difference between &lt;code&gt;pip&lt;/code&gt; and &lt;code&gt;pip3&lt;/code&gt; commands caused issues in Python setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Problem:&lt;/strong&gt; On Windows, &lt;code&gt;pip3&lt;/code&gt; is often not recognized, leading to errors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Solution:&lt;/strong&gt; Implemented a function to check for both &lt;code&gt;pip&lt;/code&gt; and &lt;code&gt;pip3&lt;/code&gt;, using whichever is available.
&lt;/li&gt;
&lt;/ul&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;getPythonCommands&lt;/span&gt; &lt;span class="o"&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;os&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;detectOS&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;pythonCmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;python3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;pipCmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pip3&lt;/span&gt;&lt;span class="dl"&gt;'&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;os&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;windows&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="nx"&gt;pythonCmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;python&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;pipCmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pip&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="c1"&gt;// Check if the commands exist; fallback if necessary&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="nf"&gt;checkCommandExists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pythonCmd&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;pythonCmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;checkCommandExists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;python&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;python&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&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="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;checkCommandExists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pipCmd&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;pipCmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;checkCommandExists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pip&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pip&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;pythonCmd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pipCmd&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;h3&gt;
  
  
  &lt;strong&gt;Ensuring Continuity After Errors&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To make EnviroX more resilient, I modified the script to continue setting up other environments even if one fails:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Implementation:&lt;/strong&gt; Wrapped each setup section in its own &lt;code&gt;try...catch&lt;/code&gt; block.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Result:&lt;/strong&gt; If, for example, Python setup fails due to a missing &lt;code&gt;pip&lt;/code&gt; installation, EnviroX will proceed to set up Node.js or Go environments.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Optimizing Code and Enhancing Maintainability&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Modularization:&lt;/strong&gt; Separated functionality into different modules for clarity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Async/Await Consistency:&lt;/strong&gt; Standardized the use of &lt;code&gt;async&lt;/code&gt; and &lt;code&gt;await&lt;/code&gt; across all functions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improved Logging:&lt;/strong&gt; Used &lt;code&gt;chalk&lt;/code&gt; and &lt;code&gt;ora&lt;/code&gt; to provide colored output and spinners, enhancing user experience.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Lessons Learned&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Developing EnviroX has been a rewarding experience filled with valuable lessons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Importance of Cross-Platform Compatibility:&lt;/strong&gt; Testing on different operating systems is crucial to identify and fix OS-specific issues.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistent Error Handling:&lt;/strong&gt; Proper error handling ensures the tool is robust and user-friendly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User Feedback Matters:&lt;/strong&gt; Providing clear feedback during execution helps users understand what's happening and builds trust.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modular Code Structure:&lt;/strong&gt; Organizing code into modules improves maintainability and scalability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community Engagement:&lt;/strong&gt; Open-source projects benefit greatly from community feedback and contributions.&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;EnviroX has come a long way from its initial flawed version. By addressing the shortcomings and implementing robust solutions, it has evolved into a reliable tool that simplifies the development environment setup process.&lt;/p&gt;

&lt;p&gt;I invite you to try out EnviroX and contribute to its ongoing development. Your feedback and contributions are invaluable in making EnviroX even better.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Get EnviroX Today&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Install via npm&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;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; envirox
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;GitHub Repository&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/neelp03/envirox" rel="noopener noreferrer"&gt;https://github.com/neelp03/envirox&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Feedback and Contributions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you encounter any issues or have suggestions, please open an issue or submit a pull request on GitHub.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Happy coding!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>webdev</category>
      <category>go</category>
      <category>beginners</category>
    </item>
    <item>
      <title>ThrottleX: Scaling to a Million Requests Per Second Without Breaking a Sweat</title>
      <dc:creator>Neel Patel</dc:creator>
      <pubDate>Tue, 22 Oct 2024 04:55:50 +0000</pubDate>
      <link>https://dev.to/neelp03/throttlex-scaling-to-a-million-requests-per-second-without-breaking-a-sweat-39n0</link>
      <guid>https://dev.to/neelp03/throttlex-scaling-to-a-million-requests-per-second-without-breaking-a-sweat-39n0</guid>
      <description>&lt;p&gt;Link: &lt;a href="https://github.com/neelp03/throttlex" rel="noopener noreferrer"&gt;https://github.com/neelp03/throttlex&lt;/a&gt;&lt;br&gt;
Scroll down if you want to test it yourself!!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Introduction:&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Handling millions of requests per second? Is that even possible? 🤯&lt;/p&gt;

&lt;p&gt;When we talk about high-scale distributed systems, things can get… complicated. You know the drill: rate-limiting is essential to prevent abuse, but it often becomes the bottleneck. What if I told you we engineered a system that can handle &lt;em&gt;1 million requests per second&lt;/em&gt; without a hitch? Meet &lt;strong&gt;ThrottleX&lt;/strong&gt;, my open-source distributed rate-limiting library written in Go.&lt;/p&gt;

&lt;p&gt;In this post, I’ll pull back the curtain and show you exactly how we achieved this mind-blowing scale. I’ll walk you through the advanced optimizations, the Go concurrency model that made it all possible, and even some surprise bottlenecks we encountered along the way. But this isn’t just theory – I’ll share the &lt;em&gt;real benchmarks&lt;/em&gt; we hit. Buckle up because we’re about to break some limits! 🚀&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Section 1: The Challenge – Why Scale Matters&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Scaling rate limiting is one of those things that seems straightforward until you try to do it at an extreme scale. Most systems are fine with a few hundred or thousand requests per second. But when you hit millions of requests, things fall apart fast:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Memory management issues&lt;/strong&gt; 🧠&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network bottlenecks&lt;/strong&gt; 🌐&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Concurrency nightmares&lt;/strong&gt; 🧵&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The trick isn’t just limiting the rate – it’s doing it &lt;em&gt;efficiently&lt;/em&gt; across multiple nodes, ensuring every request is handled with lightning speed without consuming all available resources. That’s where &lt;strong&gt;ThrottleX&lt;/strong&gt; comes in. Built for speed, designed for scale, it uses a mix of rate-limiting algorithms and real-time optimizations to stay ahead of the game.&lt;/p&gt;

&lt;p&gt;But why does this even matter? Let’s look at some real-world scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;APIs under heavy load&lt;/strong&gt;: Your API is the backbone of your app, and when traffic spikes (hello, viral moment! 📈), you need a way to handle that influx without taking everything down.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Distributed microservices&lt;/strong&gt;: When services depend on external APIs, ensuring consistent performance across millions of requests keeps the whole system stable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud-scale apps&lt;/strong&gt;: With cloud infrastructure, you need to optimize costs while managing unpredictable workloads – this is where efficient rate limiting saves the day (and your cloud bill 💸).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ThrottleX isn’t just any rate limiter – it’s designed for &lt;em&gt;extreme&lt;/em&gt; conditions, and I’ll show you exactly how we pushed it to the limit.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Section 2: Breaking it Down – The Architecture of ThrottleX&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;At the heart of ThrottleX is a &lt;strong&gt;combination of smart rate-limiting algorithms&lt;/strong&gt; and a highly optimized concurrency model. But it’s not just the algorithms – it’s how they’re implemented and how we make them scalable across distributed environments. Let’s dig into the core architecture that makes it all tick.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;1. The Algorithms Behind the Magic&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;When it comes to rate limiting, you’ve probably heard of the classics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Token Bucket&lt;/strong&gt;: Allows for bursts of traffic but refills tokens at a steady rate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sliding Window&lt;/strong&gt;: Smooths out traffic over time, counting requests in sliding time intervals.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Leaky Bucket&lt;/strong&gt;: Think of it like a bucket with a hole – requests “leak” out at a steady rate.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ThrottleX doesn’t reinvent the wheel, but we took these tried-and-true algorithms and made them &lt;em&gt;smarter&lt;/em&gt;. Here's how:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Rate Limiting&lt;/strong&gt;: We implemented a flexible system where rate limits can adapt in real-time based on traffic conditions. If traffic suddenly spikes, ThrottleX can handle the load without over-throttling, allowing for optimal throughput.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Concurrency Handling&lt;/strong&gt;: Rate-limiting can be especially tricky when handling &lt;strong&gt;concurrent&lt;/strong&gt; requests. We used &lt;strong&gt;mutex locks&lt;/strong&gt; to ensure that no race conditions occur, while still allowing maximum concurrency.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;2. Go Concurrency Model – The Secret Sauce&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;One of the reasons ThrottleX is built in &lt;strong&gt;Go&lt;/strong&gt; is its &lt;strong&gt;goroutines&lt;/strong&gt; and &lt;strong&gt;channels&lt;/strong&gt;, which give us insane concurrency with minimal overhead. Here’s why Go’s concurrency model was a game-changer for us:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Goroutines are cheap&lt;/strong&gt;: Unlike traditional threads, goroutines have a tiny memory footprint. This means we can spawn millions of them without crushing system resources.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Asynchronous Processing&lt;/strong&gt;: By processing requests asynchronously, we avoid blocking operations. This is key to keeping ThrottleX responsive under high traffic. Each request is handled in its own goroutine, with &lt;strong&gt;channels&lt;/strong&gt; facilitating communication between them for smooth coordination.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In layman’s terms, it’s like having a super-efficient assembly line – every worker (goroutine) is doing their job without waiting for someone else to finish.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;3. Distributed Storage Optimization with Redis&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;A distributed rate limiter needs a &lt;strong&gt;shared state&lt;/strong&gt;, which is where Redis comes into play. But we couldn’t just plug Redis in and call it a day – we had to &lt;strong&gt;optimize&lt;/strong&gt; it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Key Expiration Policies&lt;/strong&gt;: Redis stores key-value pairs for each rate-limited client, but setting efficient expiration times for these keys was crucial. If keys don’t expire fast enough, you waste memory; too fast, and you lose track of the rate limits. We fine-tuned the &lt;strong&gt;TTL (time-to-live)&lt;/strong&gt; to ensure we hit the sweet spot between memory efficiency and accuracy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minimizing Redis Latency&lt;/strong&gt;: Redis is already fast, but under heavy load, latency spikes can still occur. We optimized by tweaking the &lt;strong&gt;pipelining&lt;/strong&gt; and &lt;strong&gt;replication&lt;/strong&gt; settings. This let us push more requests per second while keeping the database latency under control.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;4. Batching Requests for Performance Gains&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Another trick we used to scale up is &lt;strong&gt;batching requests&lt;/strong&gt;. Instead of processing every request individually, ThrottleX batches them together in the background. This reduces the number of operations that hit the Redis backend, leading to fewer round trips and faster throughput.&lt;/p&gt;

&lt;p&gt;Think of it like sending packages through the mail. Instead of making a trip to the post office for each letter, you wait until you have a stack and send them all at once – saving time and energy.&lt;/p&gt;




&lt;p&gt;This architecture, built on the power of Go and optimized Redis configurations, gave ThrottleX the ability to handle massive traffic loads efficiently. And the best part? It’s all designed to scale with minimal tweaks, so whether you’re handling thousands or millions of requests, ThrottleX has you covered.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Section 3: The Million-Request Secret – Key Optimizations&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;So how did we actually push &lt;strong&gt;ThrottleX&lt;/strong&gt; to handle a &lt;strong&gt;million requests per second&lt;/strong&gt; without crashing the system or blowing up the infrastructure? It came down to a series of carefully crafted optimizations, both in the rate-limiting algorithms and the underlying system architecture. Here's the secret sauce:&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;1. Batching Requests for High Throughput&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;One of the biggest game-changers was &lt;strong&gt;batching requests&lt;/strong&gt;. Rather than handling every request individually, we grouped them into batches. This massively reduced the number of operations hitting our backend (Redis), leading to fewer round trips, lower latency, and faster throughput.&lt;/p&gt;

&lt;p&gt;In other words, it’s like processing a hundred requests in the time it would normally take to process ten. This optimization alone provided a &lt;strong&gt;50% increase in throughput&lt;/strong&gt; in our benchmarks.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;2. Circuit Breakers to Prevent Overload&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;When you’re handling traffic at this scale, things can and will go wrong. To keep &lt;strong&gt;ThrottleX&lt;/strong&gt; from being overwhelmed during traffic spikes, we implemented a &lt;strong&gt;circuit breaker pattern&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here’s how it works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If a service downstream (like Redis or a client service) starts lagging or fails, the circuit breaker &lt;strong&gt;trips&lt;/strong&gt;, immediately halting requests to that service.&lt;/li&gt;
&lt;li&gt;This prevents an overload, allowing the system to &lt;strong&gt;recover gracefully&lt;/strong&gt; without crashing.&lt;/li&gt;
&lt;li&gt;Once the issue is resolved, the breaker “resets,” and traffic flows normally again.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This design helps maintain &lt;strong&gt;high availability&lt;/strong&gt;, even under intense load or temporary failures in the system. Without it, ThrottleX would crumble when Redis replication lagged or when traffic surged unexpectedly.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;3. Memory Efficiency – Optimizing Goroutines and Pooling&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Concurrency is a double-edged sword. While Go’s goroutines are lightweight, they still require memory management. As we scaled, the garbage collection (GC) process became a bottleneck – eating into our performance, especially under heavy loads.&lt;/p&gt;

&lt;p&gt;Our solution? &lt;strong&gt;Pooling resources&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We reused goroutines wherever possible, reducing the memory footprint and minimizing GC overhead.&lt;/li&gt;
&lt;li&gt;We also implemented custom &lt;strong&gt;memory pools&lt;/strong&gt; for frequently used data structures to prevent constant memory allocation and deallocation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result? A &lt;strong&gt;30% reduction in memory usage&lt;/strong&gt; and much smoother performance during traffic bursts.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;4. Redis Pipeline Optimization&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;To ensure Redis could keep up with the massive request load, we fine-tuned the &lt;strong&gt;pipelining&lt;/strong&gt; feature. Instead of sending each command to Redis one at a time (which introduces latency), we bundled multiple commands together into a &lt;strong&gt;single request&lt;/strong&gt;. This allowed Redis to process batches of commands in parallel, drastically cutting down response times.&lt;/p&gt;

&lt;p&gt;The magic of Redis pipelining lies in the way it minimizes &lt;strong&gt;network I/O&lt;/strong&gt; and increases throughput. With this optimization, Redis was able to handle millions of requests per second with &lt;strong&gt;sub-millisecond latency&lt;/strong&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;5. Adaptive Rate Limiting&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;We took rate limiting to the next level by making it &lt;strong&gt;adaptive&lt;/strong&gt;. Instead of using a fixed rate across the board, ThrottleX can dynamically adjust the rate limit based on real-time traffic conditions.&lt;/p&gt;

&lt;p&gt;Imagine this: during normal traffic, the system allows for a consistent flow of requests. But during a sudden spike (say, a flash sale on an e-commerce site or a viral app moment), ThrottleX will &lt;strong&gt;temporarily relax&lt;/strong&gt; the limits, allowing more traffic to pass through without throttling too aggressively. Once the spike subsides, it automatically dials the rate back down.&lt;/p&gt;

&lt;p&gt;This adaptive approach ensures that legitimate users don’t get throttled during traffic spikes, while still protecting your backend from abuse.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;6. Real-Time Metrics and Monitoring&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;We wanted to go beyond rate limiting – we wanted &lt;strong&gt;visibility&lt;/strong&gt; into what was happening at scale. To do this, we integrated &lt;strong&gt;real-time monitoring&lt;/strong&gt; with tools like &lt;strong&gt;Prometheus&lt;/strong&gt; and &lt;strong&gt;Grafana&lt;/strong&gt;. This allowed us to track key metrics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Request throughput&lt;/strong&gt; (RPS – Requests per second)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Error rates&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Redis latency&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Goroutine utilization&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These insights allowed us to catch performance bottlenecks early and fine-tune the system before they became issues. With dashboards showing real-time traffic and system health, we could monitor ThrottleX’s performance even during peak loads.&lt;/p&gt;




&lt;p&gt;These optimizations, working together, are what unlocked the ability to handle &lt;strong&gt;1 million requests per second&lt;/strong&gt;. Each tweak, from batching and pipelining to memory optimization and adaptive rate limiting, pushed ThrottleX further into hyperscale territory. 🚀&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Section 4: Real Benchmarks – Prove It or Lose It&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Let’s be real: it’s easy to talk about optimizations, but the proof is always in the numbers. After rounds of stress testing, benchmarking, and fine-tuning, here are the &lt;strong&gt;real metrics&lt;/strong&gt; we achieved with &lt;strong&gt;ThrottleX&lt;/strong&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Benchmark Setup&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;We ran the tests using the following configuration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Environment&lt;/strong&gt;: A distributed system setup with 5 nodes, each running on a 4-core CPU with 16GB of RAM.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend&lt;/strong&gt;: Redis for shared state across the nodes, fine-tuned with pipelining and optimized key expiration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Traffic Load&lt;/strong&gt;: We simulated up to &lt;strong&gt;1 million requests per second&lt;/strong&gt; with both regular and burst traffic patterns.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tools&lt;/strong&gt;: Prometheus for monitoring and Grafana for real-time visualization of metrics.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, onto the fun part. Here are the &lt;strong&gt;results&lt;/strong&gt;:&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;1. Throughput – 1 Million Requests per Second&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Requests per Second (RPS)&lt;/strong&gt;: We consistently handled &lt;strong&gt;1 million RPS&lt;/strong&gt; across multiple nodes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Peak Traffic&lt;/strong&gt;: During burst scenarios, ThrottleX handled traffic spikes up to &lt;strong&gt;1.2 million RPS&lt;/strong&gt; without any significant drop in performance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ThrottleX handled this load while maintaining &lt;strong&gt;low latency&lt;/strong&gt; and minimal resource consumption across the board.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;2. Latency – Sub-Millisecond Response Times&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Latency is always a concern when dealing with distributed systems, especially at this scale. However, ThrottleX consistently delivered &lt;strong&gt;sub-millisecond response times&lt;/strong&gt;, even under extreme traffic.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Average Redis Latency&lt;/strong&gt;: &lt;strong&gt;0.7 ms&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Average Request Latency&lt;/strong&gt;: &lt;strong&gt;0.8 ms&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks to optimizations like Redis pipelining and batching requests, we minimized round trips to the database, keeping latency well under 1 ms.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;3. Memory Efficiency – 30% Lower Memory Usage&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;By optimizing &lt;strong&gt;goroutines&lt;/strong&gt; and &lt;strong&gt;memory pooling&lt;/strong&gt;, we achieved a &lt;strong&gt;30% reduction in memory usage&lt;/strong&gt; compared to traditional rate limiters. Here’s a breakdown:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Goroutine Pooling&lt;/strong&gt;: Reduced the overhead of spawning millions of concurrent requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom Memory Pools&lt;/strong&gt;: Significantly lowered the number of allocations during traffic bursts, leading to more stable performance and less frequent garbage collection pauses.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even with millions of requests flying through the system, ThrottleX remained memory-efficient, keeping resource consumption low.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;4. Error Rates – Less Than 0.001%&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;What’s the point of handling massive traffic if the system throws errors all over the place? Fortunately, &lt;strong&gt;ThrottleX&lt;/strong&gt; delivered rock-solid reliability:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Error Rate&lt;/strong&gt;: Less than &lt;strong&gt;0.001%&lt;/strong&gt; of requests failed or were throttled unnecessarily, even under peak load conditions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This reliability is a testament to the effectiveness of our &lt;strong&gt;adaptive rate limiting&lt;/strong&gt; and the &lt;strong&gt;circuit breaker pattern&lt;/strong&gt;, which helped prevent system overloads and cascading failures.&lt;/p&gt;




&lt;p&gt;These benchmarks aren’t just impressive on paper – they’re backed by &lt;strong&gt;real-world stress tests&lt;/strong&gt; and show that &lt;strong&gt;ThrottleX&lt;/strong&gt; is capable of handling extreme traffic loads without compromising performance.&lt;/p&gt;

&lt;p&gt;And here’s the best part: you can try it yourself! 🚀&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Try It Yourself&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;All the code and configurations I used for these benchmarks are available in the &lt;strong&gt;ThrottleX repository&lt;/strong&gt;. Fork it, run your own tests, and see if you can push it even further. The project is open-source, and I’m always excited to see what the community can bring to the table. Whether it’s improving the algorithms or optimizing for even higher throughput, I welcome contributions and ideas.&lt;/p&gt;

&lt;p&gt;Link to this example app, monitoring code: &lt;a href="https://github.com/neelp03/ThrottleX-Test" rel="noopener noreferrer"&gt;https://github.com/neelp03/ThrottleX-Test&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsvvngb6cp0ecgeyp4l92.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%2Fsvvngb6cp0ecgeyp4l92.png" alt="grafana dashboard" width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Section 5: Lessons Learned – What Surprised Us&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Building something that can handle &lt;strong&gt;1 million requests per second&lt;/strong&gt; was a wild ride, and along the way, we encountered some unexpected challenges that taught us valuable lessons. Here’s what surprised us the most and how we tackled these roadblocks.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;1. Go’s Garbage Collection – A Silent Bottleneck&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;When we first started scaling up, we noticed random spikes in response times during heavy traffic. After digging into the issue, we realized that Go’s &lt;strong&gt;garbage collection (GC)&lt;/strong&gt; was silently causing performance hiccups.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Issue&lt;/strong&gt;: With millions of goroutines flying around, GC was being triggered too often, resulting in pauses that affected latency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Fix&lt;/strong&gt;: We optimized the way memory was allocated by implementing &lt;strong&gt;custom memory pools&lt;/strong&gt; and &lt;strong&gt;reusing objects&lt;/strong&gt; where possible. This reduced the frequency of GC cycles and smoothed out performance during traffic spikes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lesson learned: Even though Go’s memory management is efficient, at scale, you need to &lt;strong&gt;micro-manage memory&lt;/strong&gt; to avoid performance bottlenecks.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;2. Redis Replication Lag – The Hidden Time Bomb&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;While Redis is fast, when dealing with millions of requests per second, we ran into &lt;strong&gt;replication lag&lt;/strong&gt;. Under heavy traffic, Redis’ ability to replicate data across nodes couldn’t keep up with the write load.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Issue&lt;/strong&gt;: Redis replication lag caused delays in syncing data between master and replica nodes, which led to inconsistent rate limits across distributed systems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Fix&lt;/strong&gt;: We reduced the replication frequency and fine-tuned Redis to favor &lt;strong&gt;high availability over consistency&lt;/strong&gt; in certain scenarios. This gave us better performance at the cost of occasional stale data, but for rate limiting, this trade-off was acceptable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lesson learned: Redis is a beast, but at massive scale, &lt;strong&gt;trade-offs between consistency and availability&lt;/strong&gt; become necessary to keep performance high.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;3. Network Latency – The Invisible Killer&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;When testing across distributed nodes, we found that &lt;strong&gt;network latency&lt;/strong&gt; was adding up quickly, especially when requests had to travel across regions. At scale, even a few milliseconds of delay multiplied across millions of requests can cause serious performance degradation.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Issue&lt;/strong&gt;: Distributed rate limiting involves constant communication between nodes and back to Redis, and even tiny network delays added up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Fix&lt;/strong&gt;: We optimized the system by &lt;strong&gt;localizing&lt;/strong&gt; as much of the rate limiting logic as possible, minimizing the number of trips to Redis. By processing requests locally first and only syncing state periodically, we reduced the overall dependency on network calls.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lesson learned: &lt;strong&gt;Minimizing network calls&lt;/strong&gt; is crucial for distributed systems. The less you depend on external communication, the more resilient and fast your system will be.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;4. Adaptive Rate Limiting – Finding the Balance&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;While &lt;strong&gt;adaptive rate limiting&lt;/strong&gt; was a game-changer, getting the balance right between allowing traffic surges and maintaining protection was trickier than expected.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Issue&lt;/strong&gt;: At first, the rate limits adjusted too aggressively, allowing too much traffic during spikes, which led to &lt;strong&gt;temporary overloads&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Fix&lt;/strong&gt;: We tweaked the algorithm to take &lt;strong&gt;longer-term traffic trends&lt;/strong&gt; into account, smoothing out the rate adjustments over time. This prevented wild swings in traffic and gave the system more breathing room during sustained traffic surges.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lesson learned: Adaptation is powerful, but it needs to be &lt;strong&gt;fine-tuned&lt;/strong&gt; to avoid over-correcting. Too much adjustment can be as dangerous as too little.&lt;/p&gt;




&lt;p&gt;Building and scaling ThrottleX taught us that &lt;strong&gt;performance at scale is all about finding the right balance&lt;/strong&gt;: balancing memory usage, network latency, replication, and rate limits. Every optimization involved trade-offs, but each challenge pushed us to build a more resilient, faster system.&lt;/p&gt;




&lt;h3&gt;
  
  
  Conclusion – Your Turn: Push ThrottleX Even Further
&lt;/h3&gt;

&lt;p&gt;ThrottleX is now a battle-tested distributed rate limiter capable of handling extreme traffic loads. But there’s always room for more! Whether you want to contribute new features, test it under different conditions, or tweak it for even better performance, the &lt;strong&gt;ThrottleX repository&lt;/strong&gt; is open and waiting for you.&lt;/p&gt;

&lt;p&gt;Let’s push the limits together and see just how far we can take this.&lt;/p&gt;

</description>
      <category>backend</category>
      <category>go</category>
      <category>webdev</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Introducing EnviroX: Your Go-To Dev Environment Setup Tool! 🛠️</title>
      <dc:creator>Neel Patel</dc:creator>
      <pubDate>Mon, 21 Oct 2024 00:57:16 +0000</pubDate>
      <link>https://dev.to/neelp03/introducing-envirox-your-go-to-dev-environment-setup-tool-281p</link>
      <guid>https://dev.to/neelp03/introducing-envirox-your-go-to-dev-environment-setup-tool-281p</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;em&gt;EDIT: Please find the latest version notes here: &lt;a href="https://dev.to/neelp03/rebuilding-envirox-overcoming-early-flaws-to-automate-development-environments-12ld"&gt;Envirox Post 2&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;Hey fellow devs! 👋&lt;/p&gt;

&lt;p&gt;I’m excited to introduce &lt;strong&gt;EnviroX&lt;/strong&gt;, a CLI tool designed to simplify setting up development environments for multiple programming languages and frameworks. Whether you’re a backend whiz or just getting started with Docker, EnviroX has you covered. Think of it as your automated setup assistant!&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;Check out the project on GitHub:&lt;/strong&gt; &lt;a href="https://github.com/neelp03/envirox" rel="noopener noreferrer"&gt;EnviroX Repository&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🌟 Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Automatic Language &amp;amp; Framework Detection&lt;/strong&gt;: EnviroX sniffs out which language (Node.js, Python, Go, etc.) you're using and installs the necessary dependencies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dependency Installation&lt;/strong&gt;: No more googling commands! EnviroX handles package managers like npm, pip, yarn, and bun.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker Support&lt;/strong&gt;: Got a Dockerfile? EnviroX will handle that too, spinning up your containerized environment in no time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-Platform&lt;/strong&gt;: Whether you’re on Linux, macOS, or Windows, EnviroX has your back.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🛠 How It Works
&lt;/h2&gt;

&lt;p&gt;Once you run the EnviroX CLI, it scans your project for configuration files, checks for missing dependencies, and installs what you need. Currently, it works for languages like Node.js, Python, and Go, but there’s a lot more coming!&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Note&lt;/strong&gt;: If you don't have Node.js installed, EnviroX will prompt you to download it manually. It's a work in progress, and we aim to make this even smoother in future updates!&lt;/p&gt;

&lt;h2&gt;
  
  
  🚧 Contributing
&lt;/h2&gt;

&lt;p&gt;EnviroX is just getting started, and there’s a LOT of work to be done! From adding new language support to streamlining package installation, there’s room for all sorts of contributions.&lt;/p&gt;

&lt;p&gt;🛠 &lt;strong&gt;Want to help out?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Jump in on the action over at &lt;a href="https://github.com/neelp03/envirox" rel="noopener noreferrer"&gt;EnviroX GitHub Repo&lt;/a&gt;. We’re actively looking for collaborators, so feel free to dive into the issues, open PRs, or share your ideas. No contribution is too small!&lt;/p&gt;

&lt;h2&gt;
  
  
  ⚖ License
&lt;/h2&gt;

&lt;p&gt;EnviroX is licensed under the &lt;strong&gt;Apache 2.0 License&lt;/strong&gt;, so feel free to fork, modify, and contribute to make it even better! Full license details can be found &lt;a href="https://github.com/neelp03/envirox/blob/main/LICENSE" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>node</category>
      <category>devops</category>
      <category>cli</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Handling Large File Uploads in Go with AWS S3: Stream Like a Pro</title>
      <dc:creator>Neel Patel</dc:creator>
      <pubDate>Sat, 19 Oct 2024 19:20:06 +0000</pubDate>
      <link>https://dev.to/neelp03/handling-large-file-uploads-in-go-with-aws-s3-stream-like-a-pro-3dle</link>
      <guid>https://dev.to/neelp03/handling-large-file-uploads-in-go-with-aws-s3-stream-like-a-pro-3dle</guid>
      <description>&lt;p&gt;In a previous post, we built a file upload service using Go with local storage and Amazon S3 for cloud-based storage. But what if you need to handle &lt;strong&gt;large files&lt;/strong&gt;—think multi-gigabyte video files, or datasets? 😅 That’s where things can get tricky. You don’t want your server bogging down or running out of memory.&lt;/p&gt;

&lt;p&gt;In this post, we’ll explore how to &lt;strong&gt;handle large file uploads efficiently&lt;/strong&gt; using &lt;strong&gt;streaming&lt;/strong&gt; and &lt;strong&gt;chunking&lt;/strong&gt; with AWS S3. This way, even the largest files won’t bring your app to its knees.&lt;/p&gt;

&lt;p&gt;Here’s what we’ll cover:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Why handling large files requires special care.&lt;/li&gt;
&lt;li&gt;Streaming large files directly to S3 with minimal memory usage.&lt;/li&gt;
&lt;li&gt;Chunking large files and reassembling them on S3.&lt;/li&gt;
&lt;li&gt;Best practices for large file uploads in a production environment.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Ready to get those large files flying into the cloud? Let’s dive in! 🌥️&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 1: Why Handling Large Files Is Different
&lt;/h3&gt;

&lt;p&gt;When dealing with large file uploads, the last thing you want is to load an entire file into memory. For smaller files, this is no big deal, but with larger files, you’ll quickly hit the limits of your server’s memory, especially when handling multiple simultaneous uploads.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Streaming&lt;/strong&gt; and &lt;strong&gt;chunking&lt;/strong&gt; are key techniques that allow you to handle these large files efficiently.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Streaming&lt;/strong&gt;: Upload files to S3 as they’re being received by the server, rather than loading the whole file into memory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chunking&lt;/strong&gt;: Break large files into smaller parts (chunks) and upload each chunk individually. This is especially useful for resuming failed uploads or for uploading in parallel.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Step 2: Streaming Large Files Directly to S3
&lt;/h3&gt;

&lt;p&gt;We’ll use the AWS SDK to &lt;strong&gt;stream the file&lt;/strong&gt; from the user’s upload request directly into S3, minimizing the amount of memory we need on the server.&lt;/p&gt;

&lt;h4&gt;
  
  
  Updating the Upload Handler
&lt;/h4&gt;

&lt;p&gt;Instead of storing the entire file in memory or on disk before uploading it to S3, we can use &lt;strong&gt;streams&lt;/strong&gt; to send the file in real-time. Let’s modify our existing &lt;code&gt;fileUploadHandler&lt;/code&gt; to handle large files more efficiently.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"io"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/aws/aws-sdk-go/aws"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/aws/aws-sdk-go/aws/session"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/aws/aws-sdk-go/service/s3"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;fileUploadHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Limit the request size (e.g., 10GB max size)&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MaxBytesReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Parse the multipart form data&lt;/span&gt;
    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseMultipartForm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"File too large"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusRequestEntityTooLarge&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Retrieve the file from the form&lt;/span&gt;
    &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FormFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"file"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Error retrieving file"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;// Set up AWS session&lt;/span&gt;
    &lt;span class="n"&gt;sess&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Region&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"us-west-1"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Error connecting to AWS"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Create the S3 client&lt;/span&gt;
    &lt;span class="n"&gt;s3Client&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;s3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sess&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Stream the file directly to S3&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s3Client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PutObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;s3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PutObjectInput&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Bucket&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"your-bucket-name"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Filename&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c"&gt;// Stream the file directly from the request&lt;/span&gt;
        &lt;span class="n"&gt;ACL&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"public-read"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Error uploading file to S3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"File uploaded successfully to S3!"&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;In this approach, the file is streamed directly from the request to S3, so you’re not storing the whole file in memory, which is a lifesaver for large files!&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 3: Chunking Large Files
&lt;/h3&gt;

&lt;p&gt;If you want to take it a step further, you can break files into &lt;strong&gt;chunks&lt;/strong&gt; on the client side and upload them in smaller pieces. This is especially useful for handling flaky connections or massive files, where restarting an upload from scratch would be painful.&lt;/p&gt;

&lt;h4&gt;
  
  
  Client-Side Chunking Example
&lt;/h4&gt;

&lt;p&gt;On the client side, break the file into smaller chunks and upload each one separately. Here’s an example using JavaScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;uploadFileInChunks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&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;chunkSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 5MB per chunk&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;totalChunks&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;ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;chunkSize&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;totalChunks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&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;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;chunkSize&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;end&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;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;chunkSize&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;chunk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;end&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;formData&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;FormData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;chunk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;chunkIndex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;filename&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/upload-chunk&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="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;formData&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Server-Side Handling of Chunks
&lt;/h4&gt;

&lt;p&gt;On the server side, you can receive these chunks and &lt;strong&gt;append them to the file&lt;/strong&gt; stored on S3:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;chunkUploadHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Parse the multipart form&lt;/span&gt;
    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseMultipartForm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Error parsing form"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Retrieve the chunk and file info&lt;/span&gt;
    &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FormFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"chunk"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Error retrieving chunk"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FormValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"filename"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;chunkIndex&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FormValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"chunkIndex"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Set up the AWS session&lt;/span&gt;
    &lt;span class="n"&gt;sess&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Region&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"us-west-1"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Error connecting to AWS"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;s3Client&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;s3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sess&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Append chunk to the file in S3 (multipart upload in AWS)&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s3Client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PutObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;s3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PutObjectInput&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Bucket&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"your-bucket-name"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;chunkIndex&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c"&gt;// Handle chunking in naming&lt;/span&gt;
        &lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ACL&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"public-read"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Error uploading chunk to S3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Chunk %s uploaded successfully!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chunkIndex&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 method allows you to upload chunks of a file independently and merge them in the cloud. It’s perfect for handling very large uploads where reliability is critical.&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 4: Best Practices for Large File Uploads
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Limit Request Sizes&lt;/strong&gt;: Always set a reasonable max request size (&lt;code&gt;MaxBytesReader&lt;/code&gt;) to prevent users from overwhelming your server.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Multipart Uploads for S3&lt;/strong&gt;: AWS S3 supports &lt;strong&gt;multipart uploads&lt;/strong&gt;, which is ideal for large files. You can upload parts in parallel and even resume failed uploads.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Secure File Uploads&lt;/strong&gt;: Ensure you validate file types and use secure connections (HTTPS) for file uploads. Sanitize file names to prevent directory traversal attacks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Progress Indicators&lt;/strong&gt;: If you’re chunking files, implement a progress indicator for a better user experience, especially for large files.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Wrapping Up
&lt;/h3&gt;

&lt;p&gt;Handling large file uploads doesn’t have to be a headache. By using streaming and chunking techniques with Go and S3, you can efficiently manage even the biggest files without tanking your server’s memory. Whether you’re building a file storage service, video platform, or media-heavy app, you’re now equipped to handle massive uploads like a pro. 🎉&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Have you implemented large file uploads in your projects?&lt;/strong&gt; Drop your experience or tips in the comments, and let’s keep the conversation going! 😎&lt;/p&gt;

</description>
      <category>go</category>
      <category>aws</category>
      <category>backend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Rate Limiting with ThrottleX</title>
      <dc:creator>Neel Patel</dc:creator>
      <pubDate>Thu, 17 Oct 2024 19:31:26 +0000</pubDate>
      <link>https://dev.to/neelp03/rate-limiting-with-throttlex-26df</link>
      <guid>https://dev.to/neelp03/rate-limiting-with-throttlex-26df</guid>
      <description>&lt;p&gt;&lt;strong&gt;Quick Links&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/neelp03/throttlex" rel="noopener noreferrer"&gt;GitHub Repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/neelp03/ThrottleX/wiki" rel="noopener noreferrer"&gt;Wiki Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;Hey there, open-source enthusiasts and Go aficionados! I'm back with a quick overview of my open-source project, ThrottleX, a distributed rate limiter for APIs. I'm still pretty new to this open-source world, so your advice is always welcome! 🤝&lt;/p&gt;

&lt;p&gt;ThrottleX is built to help you manage API traffic effectively, keeping your system smooth and fair. Whether it's preventing abuse or handling high load, ThrottleX has you covered. Let's explore some of the rate limiting algorithms that make ThrottleX powerful. 💪&lt;/p&gt;

&lt;h3&gt;
  
  
  Rate Limiting Algorithms Explained 👨‍💻
&lt;/h3&gt;

&lt;p&gt;ThrottleX comes packed with three core algorithms to help you manage your API traffic:&lt;/p&gt;

&lt;h4&gt;
  
  
  1. &lt;strong&gt;Fixed Window Rate Limiting&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;How It Works&lt;/strong&gt;: Imagine dividing time into fixed intervals. During each interval, you allow a fixed number of requests — say, 100 requests per minute. Once the window closes, the counter resets.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use Case&lt;/strong&gt;: Great for predictable traffic patterns but be wary of the "boundary issue," where many requests near the window's end can bypass the intended rate limit.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. &lt;strong&gt;Sliding Window Rate Limiting&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;How It Works&lt;/strong&gt;: It's like a moving average — instead of resetting completely at the end of each window, the rate limit "slides" across time, providing smoother control.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use Case&lt;/strong&gt;: Perfect for avoiding spikes and distributing requests more evenly.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. &lt;strong&gt;Token Bucket Rate Limiting&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;How It Works&lt;/strong&gt;: Picture a bucket that fills up with tokens at a steady rate. Requests consume tokens, and if the bucket is empty, requests are blocked until it refills.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use Case&lt;/strong&gt;: Ideal for allowing sudden bursts of traffic if tokens are saved up.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example Usage 🛠️
&lt;/h3&gt;

&lt;p&gt;Here's a simple example using the Fixed Window rate limiter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/neelp03/throttlex/ratelimiter"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/neelp03/throttlex/store"&lt;/span&gt;
    &lt;span class="s"&gt;"time"&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Initialize an in-memory store and a Fixed Window rate limiter&lt;/span&gt;
    &lt;span class="n"&gt;memStore&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewMemoryStore&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;limiter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ratelimiter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewFixedWindowLimiter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;memStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Minute&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to create limiter:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Simulate API requests&lt;/span&gt;
    &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"user1"&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;15&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;allowed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;limiter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Allow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;allowed&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Request %d allowed&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&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="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Request %d blocked&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Expected Output&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request 1 allowed
Request 2 allowed
... (up to 10 allowed)
Request 11 blocked
Request 12 blocked
... (up to 15 blocked)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What's Next for ThrottleX? 🚀
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Prioritized Rate Limiting&lt;/strong&gt;: Different priorities for different users.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Rate Limiting&lt;/strong&gt;: Adjust limits based on server load.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Concurrency Limit&lt;/strong&gt;: Manage simultaneous requests.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stay tuned for these future updates that will make ThrottleX even more powerful!&lt;/p&gt;

&lt;h3&gt;
  
  
  How You Can Contribute 🥇
&lt;/h3&gt;

&lt;p&gt;I'm still new to open source, and I'd love for you to be part of this journey! Contributions are always welcome — whether it's bug fixes, suggestions, or documentation improvements.&lt;/p&gt;

&lt;p&gt;Check out the repo: &lt;a href="https://github.com/neelp03/throttlex" rel="noopener noreferrer"&gt;ThrottleX GitHub Repo&lt;/a&gt; and give it a star if you find it useful. Feel free to open issues or pull requests — every bit helps!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Final Thoughts&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;ThrottleX is my attempt to make API rate limiting more accessible and efficient. Let's make it fun (and less of a pain)! 🎉&lt;/p&gt;

</description>
      <category>backend</category>
      <category>api</category>
      <category>go</category>
      <category>throttlex</category>
    </item>
    <item>
      <title>Building Better APIs with ThrottleX: Rate Limiting Done Right</title>
      <dc:creator>Neel Patel</dc:creator>
      <pubDate>Wed, 16 Oct 2024 21:42:18 +0000</pubDate>
      <link>https://dev.to/neelp03/building-better-apis-with-throttlex-rate-limiting-done-right-5432</link>
      <guid>https://dev.to/neelp03/building-better-apis-with-throttlex-rate-limiting-done-right-5432</guid>
      <description>&lt;p&gt;LINKS: &lt;a href="https://github.com/neelp03/throttlex" rel="noopener noreferrer"&gt;https://github.com/neelp03/throttlex&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hey Dev community! 👋 I'm pretty new to the open-source world, and I'd love any advice you might have. &lt;/p&gt;

&lt;p&gt;If you've ever built an API that needed to manage &lt;strong&gt;traffic control&lt;/strong&gt;, you know that &lt;strong&gt;rate limiting&lt;/strong&gt; is crucial for keeping things fair and efficient. Today, I'm excited to introduce you to my open-source project: &lt;strong&gt;ThrottleX&lt;/strong&gt; — a powerful, flexible, and easy-to-use rate limiter for your APIs! 🚀&lt;/p&gt;

&lt;h4&gt;
  
  
  What's ThrottleX?
&lt;/h4&gt;

&lt;p&gt;ThrottleX is a &lt;strong&gt;distributed rate-limiting library&lt;/strong&gt; for Go that helps you ensure fair use of your API resources, even under heavy load. Whether you're facing a surge of requests from a single user or want to prevent misuse, ThrottleX has you covered with multiple rate-limiting strategies.&lt;/p&gt;

&lt;h4&gt;
  
  
  Current Features 💡
&lt;/h4&gt;

&lt;p&gt;ThrottleX currently supports &lt;strong&gt;three core rate-limiting policies&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Fixed Window Rate Limiting&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Imagine you're running a small coffee shop, and you only have a certain number of espresso shots available per minute. Fixed Window limits requests to a set number during a fixed time interval — simple, effective, and great for managing bursts of API traffic.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sliding Window Rate Limiting&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sliding Window works similarly but acts like a moving average for requests. Instead of resetting entirely, it provides more &lt;strong&gt;granular control&lt;/strong&gt; over requests to avoid sudden spikes. It's like distributing your espresso shots more evenly throughout each minute to maintain steady service. ☕&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Token Bucket Rate Limiting&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This policy lets you accumulate tokens over time and spend them as needed. It's flexible, allowing for bursts of activity as long as there are enough tokens available. Think of it as someone buying multiple coffees if they've saved up enough loyalty tokens! ☕🎟️&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h4&gt;
  
  
  What's Next? Future Roadmap
&lt;/h4&gt;

&lt;p&gt;We're not done yet! Here's what we're working on for ThrottleX to make it even more versatile:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Prioritized Rate Limiting&lt;/strong&gt;: Different users, different priorities! Soon we'll be able to prioritize requests for specific users or services.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Request Token Policy&lt;/strong&gt;: Allow users to present specific tokens to increase their rate limit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exponential Backoff Rate Limiting&lt;/strong&gt;: Gradually increase wait times for clients who keep hitting the rate limits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Geographic Rate Limiting&lt;/strong&gt;: Set different rate limits based on geographic regions. 🌍&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hierarchical Rate Limiting&lt;/strong&gt;: Apply rate limits across users/groups in a hierarchical structure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Rate Limiting&lt;/strong&gt;: Adjust rate limits dynamically based on server load. 🌡️&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Request Quota Policies (Fixed/Rolling Quota)&lt;/strong&gt;: Set different quotas for users or groups over extended periods.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Concurrency Limit&lt;/strong&gt;: Limit the number of simultaneous requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Leaky Bucket Algorithm&lt;/strong&gt;: Similar to the token bucket but enforces a steady flow rate, preventing sudden bursts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We want ThrottleX to be the &lt;strong&gt;Swiss Army Knife&lt;/strong&gt; of rate limiting. 🛠️&lt;/p&gt;




&lt;h4&gt;
  
  
  How to Use ThrottleX
&lt;/h4&gt;

&lt;p&gt;Getting started with ThrottleX is simple! Add it to your Go project, and you're ready to go. Here's a quick example of using one of the policies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/neelp03/throttlex/ratelimiter"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/neelp03/throttlex/store"&lt;/span&gt;
    &lt;span class="s"&gt;"time"&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Initialize an in-memory store and a fixed window rate limiter&lt;/span&gt;
    &lt;span class="n"&gt;memStore&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewMemoryStore&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;limiter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ratelimiter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewFixedWindowLimiter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;memStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="m"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to create limiter:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Simulate requests&lt;/span&gt;
    &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"user1"&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;12&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;allowed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;limiter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Allow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;allowed&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Request %d allowed&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&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="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Request %d blocked&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&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="c"&gt;// Simulate requests from multiple clients (e.g., 25 clients)&lt;/span&gt;
    &lt;span class="n"&gt;clients&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;25&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;clients&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"client%d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;12&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;allowed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;limiter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Allow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Client %d - Error: %v&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;allowed&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Client %d - Request %d allowed&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&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="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Client %d - Request %d blocked&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&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="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;In the example above, we use &lt;strong&gt;Fixed Window Limiting&lt;/strong&gt; to restrict &lt;code&gt;user1&lt;/code&gt; to &lt;strong&gt;10 requests per minute&lt;/strong&gt;. When the 11th and 12th requests are made, they are blocked, ensuring fair usage. We also demonstrate how to simulate &lt;strong&gt;25 clients&lt;/strong&gt; making requests, each independently rate-limited.&lt;/p&gt;

&lt;h4&gt;
  
  
  Redis Example for Distributed Environments
&lt;/h4&gt;

&lt;p&gt;ThrottleX also supports Redis as a storage backend, ideal for distributed environments where you need to enforce rate limits across multiple servers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/go-redis/redis/v8"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/neelp03/throttlex/ratelimiter"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/neelp03/throttlex/store"&lt;/span&gt;
    &lt;span class="s"&gt;"time"&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"context"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Set up Redis client&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Addr&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"localhost:6379"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to connect to Redis:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Initialize a Redis store and a fixed window rate limiter&lt;/span&gt;
    &lt;span class="n"&gt;redisStore&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRedisStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;limiter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ratelimiter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewFixedWindowLimiter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;redisStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="m"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to create limiter:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Simulate requests from multiple clients (e.g., 25 clients)&lt;/span&gt;
    &lt;span class="n"&gt;clients&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;25&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;clients&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"client%d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;12&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;allowed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;limiter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Allow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Client %d - Error: %v&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;allowed&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Client %d - Request %d allowed&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&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="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Client %d - Request %d blocked&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&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="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 example demonstrates how to use Redis to enforce &lt;strong&gt;Fixed Window Limiting&lt;/strong&gt; across multiple clients. Redis enables rate limit management in a distributed setup, making ThrottleX a great choice for scaling applications.&lt;/p&gt;




&lt;h4&gt;
  
  
  Why ThrottleX? 🤔
&lt;/h4&gt;

&lt;p&gt;While there are many rate limiters available, ThrottleX is designed to be &lt;strong&gt;lightweight&lt;/strong&gt;, &lt;strong&gt;highly configurable&lt;/strong&gt;, and &lt;strong&gt;adaptable&lt;/strong&gt; for &lt;strong&gt;distributed environments&lt;/strong&gt;. With support for both &lt;strong&gt;in-memory&lt;/strong&gt; and &lt;strong&gt;Redis&lt;/strong&gt; storage, ThrottleX gives you the flexibility you need, whether you're working on small projects or deploying enterprise-grade solutions. ✨&lt;/p&gt;

&lt;h4&gt;
  
  
  Join the ThrottleX Journey 🚀
&lt;/h4&gt;

&lt;p&gt;I love the open-source community and would love for you to be part of this journey. ThrottleX is still evolving, and if you have ideas, feature requests, or want to contribute, please do! Let's make rate limiting easier and more enjoyable for everyone.&lt;/p&gt;

&lt;p&gt;The GitHub repository is here: &lt;a href="https://github.com/neelp03/throttlex" rel="noopener noreferrer"&gt;ThrottleX GitHub Repo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Drop by, give it a star ⭐ if you like it, and join the conversation!&lt;/p&gt;

&lt;h4&gt;
  
  
  Final Thoughts
&lt;/h4&gt;

&lt;p&gt;Building APIs is challenging, and ensuring they run smoothly while providing fair access is even more challenging. ThrottleX is my attempt at making that easier for developers everywhere.&lt;/p&gt;

&lt;p&gt;I can't wait to hear your thoughts and see what we can build together. Let's keep making the web better, one request at a time!&lt;/p&gt;

&lt;p&gt;Happy coding, everyone!&lt;/p&gt;




&lt;h4&gt;
  
  
  Diagrams for Better Understanding
&lt;/h4&gt;

&lt;p&gt;Here are some diagrams to help visualize how ThrottleX works:&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%2Fk6zfpeltksnamrwpnzvt.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%2Fk6zfpeltksnamrwpnzvt.png" alt="This flowchart represents how a request passes through ThrottleX, which either allows or blocks the request based on the configured rate limiting policy." width="800" height="698"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This flowchart represents how a request passes through ThrottleX, which either allows or blocks the request based on the configured rate limiting policy.&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%2Fqdqunqfg7e5yfpj4b1cy.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%2Fqdqunqfg7e5yfpj4b1cy.png" alt="This diagram shows the different rate-limiting policies currently supported by ThrottleX, all contributing to its core functionality." width="800" height="306"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This diagram shows the different rate-limiting policies currently supported by ThrottleX, all contributing to its core functionality.&lt;/p&gt;

</description>
      <category>go</category>
      <category>api</category>
      <category>backend</category>
      <category>throttlex</category>
    </item>
    <item>
      <title>Getting Started with React and the Component Lifecycle</title>
      <dc:creator>Neel Patel</dc:creator>
      <pubDate>Wed, 16 Oct 2024 07:44:32 +0000</pubDate>
      <link>https://dev.to/neelp03/getting-started-with-react-and-the-component-lifecycle-43oj</link>
      <guid>https://dev.to/neelp03/getting-started-with-react-and-the-component-lifecycle-43oj</guid>
      <description>&lt;p&gt;So, you’ve heard all the buzz about &lt;strong&gt;React&lt;/strong&gt; and want to see what it’s all about? You’re in the right place! Today, we’re going to go over the basics of React, and we’ll dive deep into the &lt;strong&gt;component lifecycle&lt;/strong&gt;—the set of methods and hooks that let you control what your components do from birth to death (okay, maybe not that dramatic).&lt;/p&gt;

&lt;p&gt;In this post, we’ll cover:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What React is and why it’s so popular.&lt;/li&gt;
&lt;li&gt;Setting up your first React app.&lt;/li&gt;
&lt;li&gt;Understanding the Component Lifecycle with both Class Components and Hooks.&lt;/li&gt;
&lt;li&gt;Practical examples of how to use lifecycle methods and hooks.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Ready? Let’s React! ⚛️&lt;/p&gt;




&lt;h3&gt;
  
  
  What is React? 🤔
&lt;/h3&gt;

&lt;p&gt;In a nutshell, &lt;strong&gt;React&lt;/strong&gt; is a JavaScript library for building user interfaces. Created by Facebook, it lets you break down complex UIs into small, reusable pieces called &lt;strong&gt;components&lt;/strong&gt;. React’s main claim to fame is its &lt;strong&gt;virtual DOM&lt;/strong&gt; which makes updates to the UI super fast. This is what makes React ideal for building fast, responsive apps!&lt;/p&gt;

&lt;h4&gt;
  
  
  Why React?
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reusable Components&lt;/strong&gt;: React components are like LEGO blocks for your app.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fast UI Updates&lt;/strong&gt;: The virtual DOM only updates what needs to be updated, keeping your app snappy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Huge Ecosystem&lt;/strong&gt;: React has tons of tools, libraries, and a massive community. Whatever you want to build, there’s probably a React package for it.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Setting Up Your First React App
&lt;/h3&gt;

&lt;p&gt;Let’s get started by creating a new React app using &lt;strong&gt;Create React App&lt;/strong&gt; (CRA), a super-easy way to bootstrap a new project.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 1: Install Node.js
&lt;/h4&gt;

&lt;p&gt;Make sure you have &lt;strong&gt;Node.js&lt;/strong&gt; installed. If not, you can download it from &lt;a href="https://nodejs.org" rel="noopener noreferrer"&gt;nodejs.org&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 2: Create Your App
&lt;/h4&gt;

&lt;p&gt;Open up your terminal and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-react-app my-first-react-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will set up a new React project with everything you need. Once it’s done, navigate to your app directory and start the development server:&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;cd &lt;/span&gt;my-first-react-app
npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open up &lt;code&gt;http://localhost:3000&lt;/code&gt; in your browser, and boom! 🎉 You’ve got a React app running.&lt;/p&gt;




&lt;h3&gt;
  
  
  Understanding the Component Lifecycle
&lt;/h3&gt;

&lt;p&gt;Now, let’s dig into the &lt;strong&gt;component lifecycle&lt;/strong&gt;. This is basically the series of events that happen from when a component is &lt;strong&gt;mounted&lt;/strong&gt; (added to the DOM), &lt;strong&gt;updated&lt;/strong&gt;, and then &lt;strong&gt;unmounted&lt;/strong&gt; (removed from the DOM).&lt;/p&gt;

&lt;h4&gt;
  
  
  Class Components and Lifecycle Methods
&lt;/h4&gt;

&lt;p&gt;Back in the day (before hooks were a thing), React components were written as &lt;strong&gt;class components&lt;/strong&gt; with special lifecycle methods to help control what the component does at each stage. Here’s a rundown of the main lifecycle methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;componentDidMount&lt;/strong&gt;: Runs after the component is added to the DOM. Perfect for API calls.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;componentDidUpdate&lt;/strong&gt;: Runs when the component updates (props or state changes).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;componentWillUnmount&lt;/strong&gt;: Runs right before the component is removed from the DOM. Great for cleanup (e.g., clearing timers).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s see these in action with an example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&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;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LifecycleDemo&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&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="s2"&gt;Constructor: Component is being created.&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="nf"&gt;componentDidMount&lt;/span&gt;&lt;span class="p"&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="s2"&gt;ComponentDidMount: Component has mounted.&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="nf"&gt;componentDidUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prevProps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prevState&lt;/span&gt;&lt;span class="p"&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="s2"&gt;ComponentDidUpdate: Component has updated.&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="nf"&gt;componentWillUnmount&lt;/span&gt;&lt;span class="p"&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="s2"&gt;ComponentWillUnmount: Component is about to be removed.&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="nx"&gt;increment&lt;/span&gt; &lt;span class="o"&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&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="p"&gt;};&lt;/span&gt;

  &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Count: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;increment&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Increment&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;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="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;LifecycleDemo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s what’s happening:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Constructor&lt;/strong&gt;: Initializes the state.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;componentDidMount&lt;/strong&gt;: Called once after the component mounts. Perfect for setting up anything that requires a DOM node.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;componentDidUpdate&lt;/strong&gt;: Called on updates (every time &lt;code&gt;count&lt;/code&gt; changes).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;componentWillUnmount&lt;/strong&gt;: Called right before the component is destroyed. Great for cleanup.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Enter Hooks: Simplifying the Lifecycle
&lt;/h3&gt;

&lt;p&gt;With the introduction of &lt;strong&gt;hooks&lt;/strong&gt; in React, you can handle component lifecycle events in &lt;strong&gt;function components&lt;/strong&gt;. Hooks are simpler, more intuitive, and remove the need for most lifecycle methods.&lt;/p&gt;

&lt;h4&gt;
  
  
  The &lt;code&gt;useEffect&lt;/code&gt; Hook
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;useEffect&lt;/code&gt; hook is the Swiss Army knife of lifecycle events. It lets you handle &lt;code&gt;componentDidMount&lt;/code&gt;, &lt;code&gt;componentDidUpdate&lt;/code&gt;, and &lt;code&gt;componentWillUnmount&lt;/code&gt; all in one place.&lt;/p&gt;

&lt;p&gt;Here’s how we’d recreate the &lt;code&gt;LifecycleDemo&lt;/code&gt; component using &lt;code&gt;useEffect&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&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;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;LifecycleDemo&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="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&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="s2"&gt;Component has mounted.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return &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="s2"&gt;Component will unmount.&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="p"&gt;[]);&lt;/span&gt; &lt;span class="c1"&gt;// Empty dependency array, so it only runs on mount/unmount&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&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="s2"&gt;Component has updated.&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="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt; &lt;span class="c1"&gt;// Runs every time `count` changes&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Count: &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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="nf"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&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="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Increment&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;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;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;LifecycleDemo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s what’s going on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The first &lt;code&gt;useEffect&lt;/code&gt; with an empty dependency array (&lt;code&gt;[]&lt;/code&gt;) runs only once, like &lt;code&gt;componentDidMount&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The second &lt;code&gt;useEffect&lt;/code&gt; runs whenever &lt;code&gt;count&lt;/code&gt; changes, similar to &lt;code&gt;componentDidUpdate&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Inside the first &lt;code&gt;useEffect&lt;/code&gt;, the &lt;code&gt;return&lt;/code&gt; statement acts like &lt;code&gt;componentWillUnmount&lt;/code&gt;, running cleanup code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hooks have definitely made handling lifecycle events in React easier and more flexible!&lt;/p&gt;




&lt;h3&gt;
  
  
  Practical Use Cases for Lifecycle Methods and Hooks
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;API Calls&lt;/strong&gt;: Use &lt;code&gt;componentDidMount&lt;/code&gt; or &lt;code&gt;useEffect&lt;/code&gt; to fetch data as soon as your component loads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Timers&lt;/strong&gt;: Set up an interval or timeout in &lt;code&gt;componentDidMount&lt;/code&gt; or &lt;code&gt;useEffect&lt;/code&gt;, and clear it in &lt;code&gt;componentWillUnmount&lt;/code&gt; or in the cleanup function inside &lt;code&gt;useEffect&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event Listeners&lt;/strong&gt;: Add listeners in &lt;code&gt;componentDidMount&lt;/code&gt; or &lt;code&gt;useEffect&lt;/code&gt;, and remove them in &lt;code&gt;componentWillUnmount&lt;/code&gt; or the &lt;code&gt;return&lt;/code&gt; cleanup function.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For example, setting up a timer looks like this with hooks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setInterval&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="s2"&gt;Timer tick&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="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;clearInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Clear the timer on unmount&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;h3&gt;
  
  
  Wrapping Up
&lt;/h3&gt;

&lt;p&gt;React’s component lifecycle (with either class methods or hooks) gives you the power to manage what happens at each stage of a component’s life. Now that you’ve got a handle on the basics, go ahead and start building some UIs with React. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What lifecycle methods do you use the most?&lt;/strong&gt; Drop a comment below and let me know how you use them, or share any tips you’ve picked up along the way. Happy coding! 😎&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Building a File Upload Service in Go</title>
      <dc:creator>Neel Patel</dc:creator>
      <pubDate>Tue, 15 Oct 2024 05:39:46 +0000</pubDate>
      <link>https://dev.to/neelp03/building-a-file-upload-service-in-go-34fj</link>
      <guid>https://dev.to/neelp03/building-a-file-upload-service-in-go-34fj</guid>
      <description>&lt;p&gt;Let’s talk file uploads. Whether you’re building the next Instagram, a CMS, or any app that involves user-generated content, you’re going to need to handle files. Today, we’re diving into the world of &lt;strong&gt;file uploads&lt;/strong&gt; with Go. We’ll set up a simple file upload service that can store files locally and, for a little extra flavor, we’ll even connect it to Amazon S3 so you can go full cloud mode. 🌥️&lt;/p&gt;

&lt;p&gt;Here’s the game plan:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Setting up a simple file upload endpoint.&lt;/li&gt;
&lt;li&gt;Handling files, storing them locally, and making sure everything works.&lt;/li&gt;
&lt;li&gt;Adding some basic validation to keep things secure.&lt;/li&gt;
&lt;li&gt;And then, we’re taking it up a notch with S3 storage.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Grab your coffee, and let’s go! ☕&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 1: Building the File Upload Endpoint
&lt;/h3&gt;

&lt;p&gt;First things first—let’s set up a basic HTTP server with a &lt;code&gt;/upload&lt;/code&gt; endpoint. For this, we’re sticking to Go’s built-in &lt;code&gt;net/http&lt;/code&gt; package because it’s straightforward and easy to use.&lt;/p&gt;

&lt;h4&gt;
  
  
  Server Setup
&lt;/h4&gt;

&lt;p&gt;Pop open your favorite editor, create a &lt;code&gt;main.go&lt;/code&gt; file, and set up a basic server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"log"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/upload"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fileUploadHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Server running on :8080"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":8080"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&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;h4&gt;
  
  
  Creating the Upload Handler
&lt;/h4&gt;

&lt;p&gt;Now let’s get to the fun part: handling file uploads! We’ll create a &lt;code&gt;fileUploadHandler&lt;/code&gt; function that’s going to handle incoming files and store them in a local directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;fileUploadHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Limit file size to 10MB. This line saves you from those accidental 100MB uploads!&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseMultipartForm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Retrieve the file from form data&lt;/span&gt;
    &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FormFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"myFile"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Error retrieving the file"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Uploaded File: %s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"File Size: %d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"MIME Header: %v&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Now let’s save it locally&lt;/span&gt;
    &lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;createFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Error saving the file"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;// Copy the uploaded file to the destination file&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Error saving the file"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusInternalServerError&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;Here’s the lowdown:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We’re grabbing the file from the form with &lt;code&gt;r.FormFile("myFile")&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;After we get the file, we’re opening (or creating) a local file and copying the contents over.&lt;/li&gt;
&lt;li&gt;This setup is great for local storage, quick prototypes, or projects that aren’t ready for cloud storage yet.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Saving the File Locally
&lt;/h4&gt;

&lt;p&gt;Let’s create the helper function &lt;code&gt;createFile&lt;/code&gt; that handles where our files go:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"os"&lt;/span&gt;
    &lt;span class="s"&gt;"path/filepath"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;createFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;File&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Create an uploads directory if it doesn’t exist&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"uploads"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsNotExist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mkdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"uploads"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0755&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Build the file path and create it&lt;/span&gt;
    &lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"uploads"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Step 2: Validating and Securing Your Files 🛡️
&lt;/h3&gt;

&lt;p&gt;Security is key! Let’s add a little validation so only approved file types make it through.&lt;/p&gt;

&lt;h4&gt;
  
  
  Validating the MIME Type
&lt;/h4&gt;

&lt;p&gt;Want to keep it safe? Let’s restrict uploads to images. Here’s how:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"io/ioutil"&lt;/span&gt;
    &lt;span class="s"&gt;"strings"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;isValidFileType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fileType&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DetectContentType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HasPrefix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fileType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"image/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// Only allow images&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;fileUploadHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// [Existing code here]&lt;/span&gt;

    &lt;span class="c"&gt;// Read the file into a byte slice to validate its type&lt;/span&gt;
    &lt;span class="n"&gt;fileBytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ioutil&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Invalid file"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;isValidFileType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fileBytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Invalid file type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusUnsupportedMediaType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Proceed with saving the file&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fileBytes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Error saving the file"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusInternalServerError&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;h3&gt;
  
  
  Step 3: Taking It to the Cloud with S3 ☁️
&lt;/h3&gt;

&lt;p&gt;Local storage is fine and all, but if you want to scale, S3 is where it’s at! Let’s connect your file upload service to Amazon S3 so you can store files in the cloud.&lt;/p&gt;

&lt;h4&gt;
  
  
  Install the AWS SDK
&lt;/h4&gt;

&lt;p&gt;To work with S3, you’ll need the AWS SDK:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go get &lt;span class="nt"&gt;-u&lt;/span&gt; github.com/aws/aws-sdk-go/aws
go get &lt;span class="nt"&gt;-u&lt;/span&gt; github.com/aws/aws-sdk-go/service/s3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Configure the S3 Client
&lt;/h4&gt;

&lt;p&gt;Let’s set up a function to connect to your S3 bucket:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"bytes"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/aws/aws-sdk-go/aws"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/aws/aws-sdk-go/aws/session"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/aws/aws-sdk-go/service/s3"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;uploadToS3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;sess&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Region&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"us-west-1"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c"&gt;// Your AWS region&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;s3Client&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;s3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sess&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s3Client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PutObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;s3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PutObjectInput&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Bucket&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"your-bucket-name"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;ACL&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"public-read"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;"your-bucket-name"&lt;/code&gt; with your actual S3 bucket name. Now, let’s tweak our upload handler to use this function.&lt;/p&gt;

&lt;h4&gt;
  
  
  Modify the Upload Handler
&lt;/h4&gt;

&lt;p&gt;Update &lt;code&gt;fileUploadHandler&lt;/code&gt; so we store the file in S3 instead of locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;fileUploadHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// [Existing code here]&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;uploadToS3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fileBytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Filename&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Error uploading to S3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusInternalServerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"File successfully uploaded to S3!"&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;And that’s it! You’ve now got a file upload service that supports both local storage and cloud storage via Amazon S3. 🔥&lt;/p&gt;




&lt;h3&gt;
  
  
  Testing It Out 🧪
&lt;/h3&gt;

&lt;p&gt;To test the upload service, you can use &lt;code&gt;curl&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:8080/upload &lt;span class="nt"&gt;-F&lt;/span&gt; &lt;span class="s2"&gt;"myFile=@path/to/your/file.jpg"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or, if you prefer a graphical interface, create a quick HTML form:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;enctype=&lt;/span&gt;&lt;span class="s"&gt;"multipart/form-data"&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"http://localhost:8080/upload"&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"POST"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"file"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"myFile"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"Upload"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Upload a file, and you should see it saved locally or in your S3 bucket.&lt;/p&gt;




&lt;h3&gt;
  
  
  Wrapping Up
&lt;/h3&gt;

&lt;p&gt;Building a file upload service is a great way to add functionality and learn about file handling, validation, and even cloud storage. Now that you’ve got the basics down, think about what’s next—whether it’s image resizing, video processing, or handling larger file types, the sky’s the limit!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Have you built a file upload service before?&lt;/strong&gt; Drop a comment below with your tips, or let me know what you’d like to see next. Happy coding! &lt;/p&gt;

</description>
      <category>aws</category>
      <category>go</category>
      <category>backend</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Using WebSockets in Go for Real-Time Communication</title>
      <dc:creator>Neel Patel</dc:creator>
      <pubDate>Sat, 12 Oct 2024 06:50:32 +0000</pubDate>
      <link>https://dev.to/neelp03/using-websockets-in-go-for-real-time-communication-4b3l</link>
      <guid>https://dev.to/neelp03/using-websockets-in-go-for-real-time-communication-4b3l</guid>
      <description>&lt;p&gt;Building apps that require real-time updates—like chat applications, live notifications, or collaborative tools—requires a communication method faster and more interactive than traditional HTTP. That’s where &lt;strong&gt;WebSockets&lt;/strong&gt; come in! Today, we’ll explore how to use WebSockets in Go, so you can add real-time functionality to your applications.&lt;/p&gt;

&lt;p&gt;In this post, we’ll cover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What WebSockets are and how they work.&lt;/li&gt;
&lt;li&gt;Setting up a WebSocket server in Go.&lt;/li&gt;
&lt;li&gt;Creating a simple WebSocket client.&lt;/li&gt;
&lt;li&gt;Handling events and maintaining connections.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s get real-time! 🕒&lt;/p&gt;




&lt;h3&gt;
  
  
  What Are WebSockets? 🤔
&lt;/h3&gt;

&lt;p&gt;WebSockets provide a full-duplex communication channel over a single, long-lived connection. Unlike traditional HTTP requests, which follow a request-response cycle, WebSockets allow the server and client to &lt;strong&gt;send and receive messages independently&lt;/strong&gt;, making it ideal for real-time applications.&lt;/p&gt;

&lt;h4&gt;
  
  
  Key Features:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Full-Duplex Communication&lt;/strong&gt;: Both the client and server can send messages independently, without waiting for a response.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Low Latency&lt;/strong&gt;: WebSockets keep a persistent connection open, reducing the delay between messages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event-Driven&lt;/strong&gt;: WebSockets handle data as events, enabling you to react instantly to incoming messages.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Setting Up a WebSocket Server in Go
&lt;/h3&gt;

&lt;p&gt;To create a WebSocket server, we’ll use the &lt;strong&gt;Gorilla WebSocket&lt;/strong&gt; package, which makes it easy to work with WebSockets in Go.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 1: Install Gorilla WebSocket
&lt;/h4&gt;

&lt;p&gt;Install the package using &lt;code&gt;go get&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go get &lt;span class="nt"&gt;-u&lt;/span&gt; github.com/gorilla/websocket
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 2: Create the WebSocket Server
&lt;/h4&gt;

&lt;p&gt;Now, let’s set up a simple WebSocket server that listens for incoming connections and echoes back any messages it receives:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/gorilla/websocket"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;upgrader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;websocket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Upgrader&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;CheckOrigin&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="c"&gt;// Allow all connections&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;handleConnections&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Upgrade initial GET request to a WebSocket&lt;/span&gt;
    &lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;upgrader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Upgrade&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// Read message from browser&lt;/span&gt;
        &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadMessage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"read error:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Received: %s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;// Write message back to browser&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;websocket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TextMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"write error:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;break&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="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/ws"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handleConnections&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"WebSocket server started on :8080"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":8080"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ListenAndServe:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&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;In this example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Upgrading&lt;/strong&gt;: We upgrade an HTTP connection to a WebSocket connection using &lt;code&gt;Upgrader&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read/Write Loop&lt;/strong&gt;: We enter a loop where we read messages from the client and echo them back.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: &lt;code&gt;CheckOrigin&lt;/code&gt; in &lt;code&gt;Upgrader&lt;/code&gt; allows all connections. In a production environment, make sure to validate the origin to avoid Cross-Site WebSocket Hijacking.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Setting Up a Simple WebSocket Client
&lt;/h3&gt;

&lt;p&gt;To test your WebSocket server, you can use an HTML client with JavaScript, which connects to the WebSocket server and sends/receives messages.&lt;/p&gt;

&lt;h4&gt;
  
  
  HTML Client Example:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;WebSocket Client&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;WebSocket Client&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"messageInput"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Enter message"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"sendMessage()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Send&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;pre&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"messages"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/pre&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;socket&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;WebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ws://localhost:8080/ws&lt;/span&gt;&lt;span class="dl"&gt;"&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;onopen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;messages&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Connected to WebSocket server&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="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;messages&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Received: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&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="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onclose&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;messages&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Disconnected from WebSocket server&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;messageInput&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&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="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;messageInput&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&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="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This HTML client:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Connects&lt;/strong&gt; to the WebSocket server at &lt;code&gt;ws://localhost:8080/ws&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sends&lt;/strong&gt; messages typed into the input box.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Displays&lt;/strong&gt; incoming messages in a &lt;code&gt;&amp;lt;pre&amp;gt;&lt;/code&gt; block, allowing you to see the server’s responses in real-time.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Handling Events in WebSockets
&lt;/h3&gt;

&lt;p&gt;With WebSockets, you can go beyond simple message echoing. Here are a few common events and how to handle them.&lt;/p&gt;

&lt;h4&gt;
  
  
  Broadcasting Messages to All Clients
&lt;/h4&gt;

&lt;p&gt;To broadcast messages to all connected clients, store each connection in a slice and loop through it to send messages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;clients&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;websocket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Conn&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// Track active clients&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;handleConnections&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;upgrader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Upgrade&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;clients&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadMessage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"read error:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clients&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c"&gt;// Broadcast message to all clients&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;clients&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;websocket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TextMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"broadcast error:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clients&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;client&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="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;Now, whenever a message is received, it’s broadcast to all connected clients. This is a common approach for chat applications or real-time updates.&lt;/p&gt;

&lt;h4&gt;
  
  
  Handling Disconnections Gracefully
&lt;/h4&gt;

&lt;p&gt;To handle client disconnections, use &lt;code&gt;defer ws.Close()&lt;/code&gt; and remove the client from the &lt;code&gt;clients&lt;/code&gt; map if the read operation fails.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clients&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&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;h4&gt;
  
  
  Ping/Pong for Connection Health
&lt;/h4&gt;

&lt;p&gt;WebSockets support &lt;strong&gt;ping/pong&lt;/strong&gt; frames to keep the connection alive and check if the client is still connected.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;ws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetPongHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;appData&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"pong received"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Best Practices for WebSockets
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Limit Connections&lt;/strong&gt;: Protect your server from being overwhelmed by limiting the number of active connections.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Close Inactive Connections&lt;/strong&gt;: Use timeouts or ping/pong frames to close inactive connections.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use TLS (wss)&lt;/strong&gt;: For security, always use &lt;strong&gt;wss&lt;/strong&gt; (WebSocket Secure) in production to encrypt the connection.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handle Errors Gracefully&lt;/strong&gt;: Always check for errors when reading from or writing to WebSockets and log them appropriately.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Final Thoughts
&lt;/h3&gt;

&lt;p&gt;WebSockets make it possible to build interactive, real-time applications that go beyond traditional request/response cycles. By setting up a WebSocket server in Go, you’re now equipped to handle real-time data with ease. Whether you’re building a chat app, live dashboard, or collaborative tool, WebSockets give you the power to create seamless, interactive experiences.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it out&lt;/strong&gt;: Set up a WebSocket server and start experimenting! Once you get the hang of it, you’ll see why WebSockets are essential for real-time applications.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;What’s Your Favorite Use Case for WebSockets?&lt;/strong&gt; Let me know in the comments, or share any tips you have for building real-time applications!&lt;/p&gt;

</description>
      <category>go</category>
      <category>webdev</category>
      <category>api</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How to Use Goroutines for Concurrent Processing in Go</title>
      <dc:creator>Neel Patel</dc:creator>
      <pubDate>Fri, 11 Oct 2024 17:55:38 +0000</pubDate>
      <link>https://dev.to/neelp03/how-to-use-goroutines-for-concurrent-processing-in-go-34ph</link>
      <guid>https://dev.to/neelp03/how-to-use-goroutines-for-concurrent-processing-in-go-34ph</guid>
      <description>&lt;p&gt;Concurrency is one of Go’s defining features, making it a fantastic language for building scalable, high-performance applications. In this post, we’ll explore &lt;strong&gt;Goroutines&lt;/strong&gt;, which allow you to run functions concurrently in Go, giving your applications a serious boost in efficiency. Whether you’re working on a web server, a data processor, or any other type of application, Goroutines can help you do more with less.&lt;/p&gt;

&lt;p&gt;Here’s what we’ll cover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What Goroutines are and how they work.&lt;/li&gt;
&lt;li&gt;How to create and use Goroutines.&lt;/li&gt;
&lt;li&gt;Synchronizing Goroutines with WaitGroups and Channels.&lt;/li&gt;
&lt;li&gt;Common pitfalls and best practices for working with Goroutines.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s get started! 🚀&lt;/p&gt;




&lt;h3&gt;
  
  
  What are Goroutines? 🤔
&lt;/h3&gt;

&lt;p&gt;Goroutines are lightweight threads managed by the Go runtime, allowing you to run functions concurrently. Unlike OS-level threads, Goroutines are much cheaper and more efficient. You can spawn thousands of Goroutines without overwhelming your system, making them ideal for concurrent tasks.&lt;/p&gt;

&lt;h4&gt;
  
  
  Key Features:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Efficient&lt;/strong&gt;: Goroutines use minimal memory and start quickly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Concurrent Execution&lt;/strong&gt;: They can run multiple functions at the same time, helping you handle tasks in parallel.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easy to Use&lt;/strong&gt;: You don’t need to deal with complex threading logic.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Creating and Using Goroutines
&lt;/h3&gt;

&lt;p&gt;Creating a Goroutine is incredibly simple: just use the &lt;code&gt;go&lt;/code&gt; keyword before a function call. Let’s look at a quick example.&lt;/p&gt;

&lt;h4&gt;
  
  
  Basic Example:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"time"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;printMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;500&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Millisecond&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="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;printMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello from Goroutine!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;// This runs concurrently&lt;/span&gt;
    &lt;span class="n"&gt;printMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello from main!"&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;In this example, &lt;code&gt;printMessage&lt;/code&gt; is called as a Goroutine with &lt;code&gt;go printMessage("Hello from Goroutine!")&lt;/code&gt;, which means it will run concurrently with the main function. &lt;/p&gt;




&lt;h3&gt;
  
  
  Synchronizing Goroutines with WaitGroups
&lt;/h3&gt;

&lt;p&gt;Since Goroutines run concurrently, they can finish in any order. To ensure all Goroutines complete before moving on, you can use a &lt;strong&gt;WaitGroup&lt;/strong&gt; from Go’s &lt;code&gt;sync&lt;/code&gt; package.&lt;/p&gt;

&lt;h4&gt;
  
  
  Example with WaitGroup:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"sync"&lt;/span&gt;
    &lt;span class="s"&gt;"time"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;printMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c"&gt;// Notify WaitGroup that the Goroutine is done&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;500&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Millisecond&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="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;

    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;printMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello from Goroutine!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;printMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello again!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c"&gt;// Wait for all Goroutines to finish&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"All Goroutines are done!"&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;Here, we’re adding &lt;code&gt;wg.Add(1)&lt;/code&gt; for each Goroutine and calling &lt;code&gt;wg.Done()&lt;/code&gt; when the Goroutine completes. Finally, &lt;code&gt;wg.Wait()&lt;/code&gt; pauses the main function until all Goroutines are done.&lt;/p&gt;




&lt;h3&gt;
  
  
  Communicating Between Goroutines with Channels
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Channels&lt;/strong&gt; are Go’s built-in way for Goroutines to communicate. They allow you to pass data safely between Goroutines, ensuring that no data races occur.&lt;/p&gt;

&lt;h4&gt;
  
  
  Basic Channel Example:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;sendData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channel&lt;/span&gt; &lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;channel&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="s"&gt;"Hello from the channel!"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;messageChannel&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;sendData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;messageChannel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;messageChannel&lt;/span&gt;  &lt;span class="c"&gt;// Receive data from the channel&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&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;In this example, &lt;code&gt;sendData&lt;/code&gt; sends a message to &lt;code&gt;messageChannel&lt;/code&gt;, and the main function receives it. Channels help synchronize Goroutines by blocking until both the sender and receiver are ready.&lt;/p&gt;

&lt;h4&gt;
  
  
  Using Buffered Channels
&lt;/h4&gt;

&lt;p&gt;You can also create &lt;strong&gt;buffered channels&lt;/strong&gt; that allow a set number of values to be stored in the channel before it blocks. This is useful when you want to manage data flow without necessarily synchronizing each Goroutine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;messageChannel&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;// Buffered channel with capacity of 2&lt;/span&gt;

    &lt;span class="n"&gt;messageChannel&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="s"&gt;"Message 1"&lt;/span&gt;
    &lt;span class="n"&gt;messageChannel&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="s"&gt;"Message 2"&lt;/span&gt;
    &lt;span class="c"&gt;// messageChannel &amp;lt;- "Message 3" // This would block as the buffer is full&lt;/span&gt;

    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;messageChannel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;messageChannel&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;Buffered channels add a little more flexibility, but it’s important to manage buffer sizes carefully to avoid deadlocks.&lt;/p&gt;




&lt;h3&gt;
  
  
  Common Pitfalls and Best Practices
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Avoid Blocking Goroutines&lt;/strong&gt;: If a Goroutine blocks and there’s no way to free it, you’ll get a deadlock. Use channels or context cancellation to avoid this.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use &lt;code&gt;select&lt;/code&gt; with Channels&lt;/strong&gt;: When working with multiple channels, the &lt;code&gt;select&lt;/code&gt; statement lets you handle whichever channel is ready first, avoiding potential blocking.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;   &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;channel1&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
       &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Received from channel1:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;channel2&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
       &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Received from channel2:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
       &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"No data received"&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;ol&gt;
&lt;li&gt;
&lt;strong&gt;Properly Close Channels&lt;/strong&gt;: Closing channels signals that no more data will be sent, which is useful for indicating when a Goroutine is done sending data.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;   &lt;span class="nb"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;messageChannel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Monitor Memory Usage&lt;/strong&gt;: Since Goroutines are so lightweight, it’s easy to spawn too many. Monitor your application’s memory usage to avoid overloading the system.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use Context for Cancellation&lt;/strong&gt;: When you need to cancel Goroutines, use Go’s &lt;code&gt;context&lt;/code&gt; package to propagate cancellation signals.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;   &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cancel&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithCancel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
   &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

   &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
               &lt;span class="k"&gt;return&lt;/span&gt;
           &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
               &lt;span class="c"&gt;// Continue processing&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="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Final Thoughts
&lt;/h3&gt;

&lt;p&gt;Goroutines are a powerful feature in Go, making concurrent programming accessible and effective. By leveraging Goroutines, WaitGroups, and Channels, you can build applications that handle tasks concurrently, scale efficiently, and make full use of modern multi-core processors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it out&lt;/strong&gt;: Experiment with Goroutines in your own projects! Once you get the hang of them, you’ll find that they open up a whole new world of possibilities for Go applications. Happy coding! 🎉&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;What’s Your Favorite Use Case for Goroutines?&lt;/strong&gt; Let me know in the comments, or share any other tips you have for using Goroutines effectively!&lt;/p&gt;

</description>
      <category>go</category>
      <category>concurrency</category>
      <category>backend</category>
      <category>api</category>
    </item>
    <item>
      <title>Building RESTful APIs with Go</title>
      <dc:creator>Neel Patel</dc:creator>
      <pubDate>Thu, 10 Oct 2024 17:47:11 +0000</pubDate>
      <link>https://dev.to/neelp03/building-restful-apis-with-go-3ob6</link>
      <guid>https://dev.to/neelp03/building-restful-apis-with-go-3ob6</guid>
      <description>&lt;p&gt;Welcome to Part 2 of our &lt;strong&gt;Backend Engineering for Full Stack Devs&lt;/strong&gt; series! 🚀 Today, we’re diving into one of the most fundamental topics: &lt;strong&gt;Building RESTful APIs&lt;/strong&gt; with Go. Whether you’re building an internal tool or a public API, understanding how to structure and implement RESTful endpoints is key.&lt;/p&gt;

&lt;p&gt;In this post, we’ll cover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What makes an API &lt;strong&gt;RESTful&lt;/strong&gt; (and why it matters).&lt;/li&gt;
&lt;li&gt;How to design &lt;strong&gt;endpoints&lt;/strong&gt; and handle HTTP methods.&lt;/li&gt;
&lt;li&gt;Building a simple CRUD API with Go’s &lt;code&gt;net/http&lt;/code&gt; package and &lt;strong&gt;Gorilla Mux&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Handling &lt;strong&gt;JSON requests and responses&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By the end, you’ll have a solid grasp of how to design and implement scalable RESTful APIs in Go. Let’s get started! 🎉&lt;/p&gt;




&lt;h3&gt;
  
  
  What Makes an API RESTful? 🤔
&lt;/h3&gt;

&lt;p&gt;Before we dive into the code, let’s quickly go over what makes an API &lt;strong&gt;RESTful&lt;/strong&gt;. REST (Representational State Transfer) is an architectural style for building APIs that follow these principles:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Stateless&lt;/strong&gt;: Each request from the client must contain all the necessary information to process it. The server doesn’t store session information.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource-Oriented&lt;/strong&gt;: URLs represent resources, like &lt;code&gt;/users&lt;/code&gt;, &lt;code&gt;/products&lt;/code&gt;, or &lt;code&gt;/orders&lt;/code&gt;, and HTTP methods define the actions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTTP Methods&lt;/strong&gt;: RESTful APIs use HTTP methods to specify actions:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;GET&lt;/code&gt;: Retrieve data.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;POST&lt;/code&gt;: Create new resources.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PUT&lt;/code&gt;: Update existing resources.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DELETE&lt;/code&gt;: Remove resources.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use of HTTP Status Codes&lt;/strong&gt;: RESTful APIs make good use of HTTP status codes (&lt;code&gt;200&lt;/code&gt; for success, &lt;code&gt;404&lt;/code&gt; for not found, etc.).&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Setting Up Your Go Project
&lt;/h3&gt;

&lt;p&gt;Let’s build a basic &lt;strong&gt;CRUD API&lt;/strong&gt; for managing users using Go and the &lt;strong&gt;Gorilla Mux&lt;/strong&gt; router. Our API will have the following endpoints:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;HTTP Method&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Endpoint&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Action&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GET&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/users&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Retrieve all users&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GET&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/users/{id}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Retrieve a specific user&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;POST&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/users&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Create a new user&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PUT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/users/{id}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Update an existing user&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DELETE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/users/{id}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Delete a user&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  Step 1: Install Dependencies
&lt;/h4&gt;

&lt;p&gt;First, install the &lt;strong&gt;Gorilla Mux&lt;/strong&gt; router for routing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go get &lt;span class="nt"&gt;-u&lt;/span&gt; github.com/gorilla/mux
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a simple &lt;code&gt;main.go&lt;/code&gt; file to get started:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"log"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/gorilla/mux"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRouter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;// Define routes here&lt;/span&gt;
    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Server started on :8080"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":8080"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&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;h3&gt;
  
  
  Step 2: Define the Handlers
&lt;/h3&gt;

&lt;p&gt;Now, let’s define our API handlers. These will correspond to our CRUD actions. We’ll use a simple in-memory map to store user data for this example.&lt;/p&gt;

&lt;h4&gt;
  
  
  In-Memory Data Store
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ID&lt;/span&gt;   &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"id"`&lt;/span&gt;
    &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"name"`&lt;/span&gt;
    &lt;span class="n"&gt;Age&lt;/span&gt;  &lt;span class="kt"&gt;int&lt;/span&gt;    &lt;span class="s"&gt;`json:"age"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 3: Implement CRUD Handlers
&lt;/h4&gt;

&lt;p&gt;We’ll implement each CRUD operation: &lt;strong&gt;Create&lt;/strong&gt;, &lt;strong&gt;Read&lt;/strong&gt;, &lt;strong&gt;Update&lt;/strong&gt;, and &lt;strong&gt;Delete&lt;/strong&gt; users.&lt;/p&gt;

&lt;h5&gt;
  
  
  &lt;code&gt;GET /users&lt;/code&gt; – Retrieve All Users
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;getUsers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;userList&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;userList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userList&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewEncoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userList&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;h5&gt;
  
  
  &lt;code&gt;GET /users/{id}&lt;/code&gt; – Retrieve a Specific User
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Vars&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;found&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;found&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"User not found"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusNotFound&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewEncoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&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;h5&gt;
  
  
  &lt;code&gt;POST /users&lt;/code&gt; – Create a New User
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewDecoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusCreated&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewEncoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&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;h5&gt;
  
  
  &lt;code&gt;PUT /users/{id}&lt;/code&gt; – Update an Existing User
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;updateUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Vars&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;found&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;found&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"User not found"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusNotFound&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewDecoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&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;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c"&gt;// Ensure the ID stays the same&lt;/span&gt;
    &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewEncoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&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;h5&gt;
  
  
  &lt;code&gt;DELETE /users/{id}&lt;/code&gt; – Delete a User
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;deleteUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Vars&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;found&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;found&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"User not found"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusNotFound&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusNoContent&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;h3&gt;
  
  
  Step 4: Register Routes
&lt;/h3&gt;

&lt;p&gt;Now that we’ve defined our handlers, let’s add the routes to our router in the &lt;code&gt;main&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRouter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/users"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;getUsers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Methods&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/users/{id}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Methods&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/users"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Methods&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"POST"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/users/{id}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;updateUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Methods&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"PUT"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/users/{id}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;deleteUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Methods&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DELETE"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Server started on :8080"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":8080"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&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;h3&gt;
  
  
  Step 5: Testing the API
&lt;/h3&gt;

&lt;p&gt;You can test your API using &lt;strong&gt;Postman&lt;/strong&gt; or &lt;code&gt;curl&lt;/code&gt; commands. Here’s how you can create a new user and retrieve users:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create a New User&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:8080/users &lt;span class="se"&gt;\&lt;/span&gt;
   &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
   &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"id":"1", "name":"John Doe", "age":30}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Get All Users&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   curl &lt;span class="nt"&gt;-X&lt;/span&gt; GET http://localhost:8080/users
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Get a Specific User&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   curl &lt;span class="nt"&gt;-X&lt;/span&gt; GET http://localhost:8080/users/1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Update a User&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   curl &lt;span class="nt"&gt;-X&lt;/span&gt; PUT http://localhost:8080/users/1 &lt;span class="se"&gt;\&lt;/span&gt;
   &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
   &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"name":"John Smith", "age":31}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Delete a User&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   curl &lt;span class="nt"&gt;-X&lt;/span&gt; DELETE http://localhost:8080/users/1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Best Practices for Building RESTful APIs
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Use Proper HTTP Methods&lt;/strong&gt;: Follow RESTful principles by using &lt;code&gt;GET&lt;/code&gt; for reads, &lt;code&gt;POST&lt;/code&gt; for creates, &lt;code&gt;PUT&lt;/code&gt; for updates, and &lt;code&gt;DELETE&lt;/code&gt; for deletes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Return Appropriate Status Codes&lt;/strong&gt;: Always use correct HTTP status codes (e.g., &lt;code&gt;201 Created&lt;/code&gt; for successful resource creation, &lt;code&gt;404 Not Found&lt;/code&gt; for missing resources).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handle Errors Gracefully&lt;/strong&gt;: Don’t expose internal errors to users. Use generic messages like "User not found" or "Invalid request."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Pagination for Large Data Sets&lt;/strong&gt;: When returning large lists (like &lt;code&gt;/users&lt;/code&gt;), implement pagination to prevent excessive data loading.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secure Your API&lt;/strong&gt;: Use authentication methods like JWT or OAuth2 to secure sensitive endpoints.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  What’s Next?
&lt;/h3&gt;

&lt;p&gt;Now that we’ve built a basic RESTful API, it’s time to &lt;strong&gt;integrate database support&lt;/strong&gt; so we can persist our data. In the next post, we’ll dive into using an ORM to connect our Go API to a database. Stay tuned for Part 3! 📦&lt;/p&gt;

</description>
      <category>fullstack</category>
      <category>restapi</category>
      <category>backend</category>
      <category>go</category>
    </item>
  </channel>
</rss>
