<?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: Priyanshu Verma</title>
    <description>The latest articles on DEV Community by Priyanshu Verma (@priyanshuverma).</description>
    <link>https://dev.to/priyanshuverma</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%2F994703%2F071b4abb-44c9-4685-aa5a-04f98019e345.png</url>
      <title>DEV Community: Priyanshu Verma</title>
      <link>https://dev.to/priyanshuverma</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/priyanshuverma"/>
    <language>en</language>
    <item>
      <title>Why I’m Shifting From TypeScript to Rust This Year</title>
      <dc:creator>Priyanshu Verma</dc:creator>
      <pubDate>Thu, 12 Feb 2026 15:57:59 +0000</pubDate>
      <link>https://dev.to/priyanshuverma/why-im-shifting-from-typescript-to-rust-this-year-3o2e</link>
      <guid>https://dev.to/priyanshuverma/why-im-shifting-from-typescript-to-rust-this-year-3o2e</guid>
      <description>&lt;p&gt;This year I made a decision that feels uncomfortable but necessary. I’m shifting my primary focus from TypeScript to Rust.&lt;/p&gt;

&lt;p&gt;This is not a dramatic rage-quit. It’s not “TypeScript is bad.” It’s not hype chasing. I still respect TypeScript. I still use it. The browser understands JavaScript and nothing else, so obviously TypeScript will always be part of modern development. But relying on it as my core long-term skill no longer feels right.&lt;/p&gt;

&lt;p&gt;This shift is about depth. It’s about leverage. It’s about choosing friction now to gain strength later.&lt;/p&gt;

&lt;p&gt;For the last few years, TypeScript has been comfortable. Extremely productive. You can build full-stack apps quickly. The ecosystem is massive. Documentation is everywhere. You hit a problem, search it, and there are already ten answers. AI tools autocomplete entire features in seconds. It feels like flying.&lt;/p&gt;

&lt;p&gt;But that comfort started bothering me.&lt;/p&gt;

&lt;p&gt;When something becomes that smooth, that frictionless, you have to ask yourself what is actually defensible about your skill.&lt;/p&gt;

&lt;p&gt;The reality is this: AI models are exceptionally good at JavaScript and TypeScript. The training data is enormous. Patterns are repetitive. The runtime is forgiving. Even senior-level TypeScript code can be generated in seconds. That doesn’t make TypeScript useless. It just means the barrier to output is extremely low, for both humans and machines.&lt;/p&gt;

&lt;p&gt;And when a skill becomes low-friction for machines, its long-term defensibility changes.&lt;/p&gt;

&lt;p&gt;This is the uncomfortable part people avoid talking about.&lt;/p&gt;

&lt;p&gt;If you are only building in a language that AI understands better than you do, you are competing with a tool that doesn’t get tired and doesn’t need context switches. That’s not a great long-term strategy.&lt;/p&gt;

&lt;p&gt;So I started thinking differently.&lt;/p&gt;

&lt;p&gt;What if instead of optimizing for speed of building, I optimize for depth of understanding?&lt;/p&gt;

&lt;p&gt;That’s where Rust entered seriously.&lt;/p&gt;

&lt;p&gt;Rust is not just another backend framework. It’s not a “Node alternative.” It’s a systems language. That distinction matters. With Rust you can build web servers, sure. But you can also build operating systems. Game engines. Networking stacks. Embedded firmware. Database engines. Compilers. You can compile to Linux, Windows, macOS, ARM, and even bare-metal. You can run without an operating system at all.&lt;/p&gt;

&lt;p&gt;That changes how you think.&lt;/p&gt;

&lt;p&gt;You are no longer just writing API routes. You are dealing with memory layout, ownership, concurrency models, lifetimes, deterministic behavior. You are closer to the machine. That proximity forces you to understand what is actually happening.&lt;/p&gt;

&lt;p&gt;TypeScript is about developer experience. Rust is about system integrity.&lt;/p&gt;

&lt;p&gt;And I’m starting to prefer system integrity.&lt;/p&gt;

&lt;p&gt;One of the biggest reasons is how Rust handles correctness. The Rust compiler is relentless. People joke about the borrow checker, but it’s not just a technical feature. It’s a philosophy. The compiler does not trust you. Even if you are confident your program will work, Rust will question every edge case.&lt;/p&gt;

&lt;p&gt;And this reminds me of something very simple.&lt;/p&gt;

&lt;p&gt;The Rust compiler is like your mom.&lt;/p&gt;

&lt;p&gt;Imagine you say, “I want to go on a road trip.”&lt;/p&gt;

&lt;p&gt;You are confident. You have planned everything. You know how to drive. You are excited.&lt;/p&gt;

&lt;p&gt;And your mom says, “What if the car crashes?”&lt;/p&gt;

&lt;p&gt;You respond, “That won’t happen.”&lt;/p&gt;

&lt;p&gt;She says, “What if it does?”&lt;/p&gt;

&lt;p&gt;You say, “That’s hypothetical.”&lt;/p&gt;

&lt;p&gt;She says, “Still. What if?”&lt;/p&gt;

&lt;p&gt;That is Rust.&lt;/p&gt;

&lt;p&gt;Even when you are sure everything is fine, Rust forces you to think about the hypothetical crash. What if this reference outlives its owner? What if this task shuts down mid-execution? What if this error isn’t handled? What if this memory is accessed concurrently? What if the network drops? What if the process exits early?&lt;/p&gt;

&lt;p&gt;It doesn’t accept optimism. It demands preparation.&lt;/p&gt;

&lt;p&gt;And that’s exhausting at first.&lt;/p&gt;

&lt;p&gt;Rust is not dopamine-friendly. It does not give you the instant satisfaction that scripting languages do. You don’t just write code and watch it magically run. You fight the compiler. You refactor. You restructure. You rethink ownership. You redesign your data flow. Sometimes you feel like you are losing to a machine.&lt;/p&gt;

&lt;p&gt;But something changes after a while.&lt;/p&gt;

&lt;p&gt;You realize the compiler is not fighting you. It’s training you.&lt;/p&gt;

&lt;p&gt;It forces you to think in systems. It forces you to think about failure before failure happens. It forces you to design intentionally. That kind of discipline is uncomfortable but powerful.&lt;/p&gt;

&lt;p&gt;TypeScript gives you fast iteration. Rust gives you strong guarantees.&lt;/p&gt;

&lt;p&gt;TypeScript gives you flexibility at runtime. Rust gives you certainty at compile time.&lt;/p&gt;

&lt;p&gt;TypeScript gives you speed of shipping. Rust gives you durability of shipping.&lt;/p&gt;

&lt;p&gt;And I started asking myself what I want more of.&lt;/p&gt;

&lt;p&gt;Another major factor is deployment philosophy. I’ve grown tired of runtime stacks layered on runtime stacks. Node behind reverse proxies inside containers inside cloud abstractions. Hundreds of megabytes deployed for something that fundamentally just responds to HTTP requests.&lt;/p&gt;

&lt;p&gt;With Rust, you can compile a backend and embed a compiled frontend into a single binary. No Node runtime. No reverse proxy required. No external dependencies. Copy the binary to a Raspberry Pi and run it. It works. It doesn’t ask what version of something is installed. It doesn’t need npm install. It doesn’t need Docker if you don’t want it.&lt;/p&gt;

&lt;p&gt;That simplicity is addictive.&lt;/p&gt;

&lt;p&gt;It feels honest.&lt;/p&gt;

&lt;p&gt;You build something. You compile it. You ship the artifact. That artifact is the product. There is something clean about that model. One more thing is that it is a binary even if someone gets it. they cannot see the code that we can say is a security feature. &lt;/p&gt;

&lt;p&gt;Now, why not Go?&lt;/p&gt;

&lt;p&gt;Go is good. I respect it. It compiles fast. It has strong concurrency primitives. It’s pragmatic. But for me, personally, it never felt expressive enough. The syntax feels procedural in a way that doesn’t match how I think. I come from an object-oriented background, and while Rust isn’t traditional OOP, its type system feels far more expressive and powerful.&lt;/p&gt;

&lt;p&gt;More importantly, Go isn’t a systems language in the same sense. You cannot compile Go to true bare-metal targets the way you can with Rust. Rust’s reach is broader. That matters to me. I don’t want to just write web servers for the rest of my life. I want the option to go deeper.&lt;/p&gt;

&lt;p&gt;This isn’t about language wars. It’s about surface area of capability.&lt;/p&gt;

&lt;p&gt;Rust expands mine.&lt;/p&gt;

&lt;p&gt;There’s also timing. Rust is modern but still relatively young in mainstream adoption. The market is growing. The ecosystem is maturing. But it’s not saturated. Becoming deeply competent in Rust today feels like investing early in something foundational.&lt;/p&gt;

&lt;p&gt;And beyond market thinking, it feels intellectually honest. Rust makes you slower in the beginning. It removes shortcuts. It punishes careless assumptions. It makes you confront complexity directly instead of hiding it under runtime flexibility.&lt;/p&gt;

&lt;p&gt;It is not beginner friendly. It is not easy. And that’s precisely why it’s valuable.&lt;/p&gt;

&lt;p&gt;If someone wants instant feedback, fast feature velocity, and quick wins, Rust will feel like a nightmare. The compiler errors can be brutal. You might write code that logically makes sense, and Rust will reject it for lifetime reasons you didn’t even consider. It feels unfair at first.&lt;/p&gt;

&lt;p&gt;But over time, you realize it’s making you sharper.&lt;/p&gt;

&lt;p&gt;You start anticipating ownership issues before writing code. You design APIs differently. You think about shutdown signals. You think about memory footprint. You think about concurrency boundaries. You think about determinism.&lt;/p&gt;

&lt;p&gt;You stop assuming things will work. You prove that they will.&lt;/p&gt;

&lt;p&gt;That’s a different mindset.&lt;/p&gt;

&lt;p&gt;I am not abandoning TypeScript. That would be unrealistic. The browser speaks JavaScript. Frontend ecosystems are deeply tied to it. Even if you use WebAssembly, JavaScript is still there. So TypeScript will remain part of my workflow.&lt;/p&gt;

&lt;p&gt;But I don’t want it to be my only layer of competence.&lt;/p&gt;

&lt;p&gt;Relying solely on TypeScript feels narrow. Rust feels expansive.&lt;/p&gt;

&lt;p&gt;This shift is not about rejecting comfort for the sake of pain. It’s about choosing growth over convenience. I know this year will be slower in terms of output. I know I will spend more time reading compiler errors than shipping features. But I also know that the understanding I build will compound.&lt;/p&gt;

&lt;p&gt;In a world where AI can generate boilerplate instantly, the real advantage is not how fast you can scaffold an app. It’s how deeply you understand the systems you are building on.&lt;/p&gt;

&lt;p&gt;Rust pushes you toward that depth whether you like it or not.&lt;/p&gt;

&lt;p&gt;And maybe that’s what I need right now.&lt;/p&gt;

&lt;p&gt;Not speed. Not comfort. Not instant validation.&lt;/p&gt;

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

&lt;p&gt;That’s why I’m shifting.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>rust</category>
      <category>programming</category>
    </item>
    <item>
      <title>Homelabing - Local to online setup suppressing CGNAT</title>
      <dc:creator>Priyanshu Verma</dc:creator>
      <pubDate>Thu, 25 Dec 2025 12:44:45 +0000</pubDate>
      <link>https://dev.to/priyanshuverma/homelabing-local-to-online-setup-suppressing-cgnat-mpd</link>
      <guid>https://dev.to/priyanshuverma/homelabing-local-to-online-setup-suppressing-cgnat-mpd</guid>
      <description>&lt;p&gt;In the journey of creating a Hub before we start programming or building website lets setup Pi in a way where we can access it on mobile internet. &lt;br&gt;
For that we can use Cloudflare Tunnel or Tail Scale, but the problem is both are overpowered for this setup I don't want to use Cloudflare as an intercept between Me and my data. I can't trust any 3rd Party. So, not going to use that. I will not use Tail Scale because some features are awesome. But, it to use it I need to make accounts and every new person joins the network need to create an account on Tail Scale and I don't think. I will create an account on 3rd party to access my self-hosted server.&lt;br&gt;
Now, This leads to setup my own VPN on Pi and connect to devices when I want to connect with Mobile network.&lt;/p&gt;

&lt;p&gt;For That, I will be going to use &lt;a href="https://www.wireguard.com/" rel="noopener noreferrer"&gt;WireGuard&lt;/a&gt;.&lt;br&gt;
Why? Because it is open-source light and free.&lt;br&gt;
Let's set it up.&lt;/p&gt;

&lt;p&gt;Installing WireGuard on 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="nb"&gt;sudo &lt;/span&gt;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;wireguard &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And verify by printing it's version&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wg &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, for this to work, we need to create Pi's Private and Public Keys. To create, follow this.&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 mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /etc/wireguard
&lt;span class="nb"&gt;sudo chmod &lt;/span&gt;700 /etc/wireguard
&lt;span class="nb"&gt;sudo &lt;/span&gt;wg genkey | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; /etc/wireguard/server_private.key | &lt;span class="nb"&gt;sudo &lt;/span&gt;wg pubkey | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; /etc/wireguard/server_public.key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, you will find,&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="nt"&gt;-rw-------&lt;/span&gt; 1 root root 45 server_private.key
&lt;span class="nt"&gt;-rw-------&lt;/span&gt; 1 root root 45 server_public.key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;inside &lt;code&gt;/etc/wireguard&lt;/code&gt; if not, then regenerate the keys.&lt;/p&gt;

&lt;p&gt;For me, it worked. Now let's add some config.&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;nano /etc/wireguard/wg0.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This config&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[Interface]&lt;/span&gt;
&lt;span class="py"&gt;Address&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;10.10.0.1/24&lt;/span&gt;
&lt;span class="py"&gt;ListenPort&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;51820&lt;/span&gt;
&lt;span class="py"&gt;PrivateKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;PASTE server_private.key CONTENT&amp;gt;&lt;/span&gt;
&lt;span class="py"&gt;SaveConfig&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I am using &lt;code&gt;10.10.0.1/24&lt;/code&gt; for subnet, as It is easy to remember for me and will not conflict with anything.&lt;br&gt;
Now I will enable IP forwarding&lt;br&gt;
by adding &lt;code&gt;net.ipv4.ip_forward=1&lt;/code&gt; inside &lt;code&gt;/etc/sysctl.conf&lt;/code&gt; and apply the changes with.&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;sysctl &lt;span class="nt"&gt;-p&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It should output &lt;code&gt;1&lt;/code&gt;&lt;br&gt;
Now, let's enable wireguard&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;systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;wg-quick@wg0
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl start wg-quick@wg0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and verify with &lt;code&gt;sudo wg&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now it is time to install WireGuard Official Android app on mobile and add it as a Peer.&lt;br&gt;
Will create a new tunnel generate public and private keys then on Pi in &lt;code&gt;/etc/wireguard/wg0.conf&lt;/code&gt; will add peer in bottom.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[Peer]&lt;/span&gt;
&lt;span class="py"&gt;PublicKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;PHONE_PUBLIC_KEY&amp;gt;&lt;/span&gt;
&lt;span class="py"&gt;AllowedIPs&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;10.10.0.2/32&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and reload &lt;code&gt;wg&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;&lt;span class="nb"&gt;sudo &lt;/span&gt;wg-quick down wg0
&lt;span class="nb"&gt;sudo &lt;/span&gt;wg-quick up wg0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;finally on mobile WireGuard will add&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Address &lt;span class="o"&gt;=&lt;/span&gt; 10.10.0.2/32
DNS &lt;span class="o"&gt;=&lt;/span&gt; 192.168.1.1 &lt;span class="c"&gt;# your gateway IP&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and add a Peer over there&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="py"&gt;PublicKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;SERVER_PUBLIC_KEY&amp;gt;&lt;/span&gt;
&lt;span class="py"&gt;Endpoint&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;YOUR_PUBLIC_IP&amp;gt;:51820&lt;/span&gt;
&lt;span class="py"&gt;AllowedIPs&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;0.0.0.0/0&lt;/span&gt;
&lt;span class="py"&gt;PersistentKeepalive&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;25&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now at this point I don't have a static Public IP as my ISP don't know me doing homelabing. If you are able to get static IP then use it otherwise there is one workaround.&lt;br&gt;
I will use &lt;strong&gt;DuckDNS&lt;/strong&gt;, this will help me to mimic my dynamic IP to look like static and on top of it. It is free, Lightweight and No vendor lock-in also it is not a proxy but a DNS record. To hook it go to &lt;a href="https://www.duckdns.org" rel="noopener noreferrer"&gt;https://www.duckdns.org&lt;/a&gt;&lt;br&gt;
create an account and add a domain name it whatever you want, it is not a public address just a link to your public IP. &lt;br&gt;
and use that subdomain as an endpoint.&lt;/p&gt;

&lt;p&gt;We need to make a &lt;code&gt;cron&lt;/code&gt; job to update the latest IP on DDNS. For that on Pi will create a Script to do that.&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;apt &lt;span class="nb"&gt;install &lt;/span&gt;curl &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/duckdns
nano ~/duckdns/update.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;using this&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;#!/bin/bash&lt;/span&gt;
&lt;span class="nb"&gt;echo &lt;/span&gt;&lt;span class="nv"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://www.duckdns.org/update?domains={YOUR_SUBDOMAIN}&amp;amp;token={YOUR_TOKEN}&amp;amp;ip="&lt;/span&gt; | curl &lt;span class="nt"&gt;-k&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; ~/duckdns/duck.log &lt;span class="nt"&gt;-K&lt;/span&gt; -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update &lt;code&gt;YOUR_TOKEN&lt;/code&gt; from DDNS token and &lt;code&gt;YOUR_SUBDOMAIN&lt;/code&gt; with your own subdomain.&lt;br&gt;
Now give some permissions and test it.&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;chmod&lt;/span&gt; +x ~/duckdns/update.sh
./duckdns/update.sh
&lt;span class="nb"&gt;cat&lt;/span&gt; ~/duckdns/duck.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It should give &lt;code&gt;OK&lt;/code&gt;. NOT &lt;code&gt;KO&lt;/code&gt; if it says &lt;code&gt;KO&lt;/code&gt; then you are &lt;code&gt;KO&lt;/code&gt; setup failed check your token and subdomain.&lt;br&gt;
Now let's add a &lt;code&gt;cron&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;crontab &lt;span class="nt"&gt;-e&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and adding this to run every 5 minutes&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;*/5 * * * * ~/duckdns/update.sh &amp;gt;/dev/null 2&amp;gt;&amp;amp;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's try to connect turn VPN on in mobile it should connect and by running&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;wg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will see a device connected saying&lt;br&gt;
&lt;code&gt;latest handshake: X seconds ago&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If not then Hello my friend me too. Our ISP uses &lt;code&gt;CGNAT&lt;/code&gt; (Carrier-Grade Network Address Translation) so they can control the router and as a user we cannot forward and port on IPv4.&lt;/p&gt;

&lt;p&gt;Then, What to do??&lt;br&gt;
You know what, after hours of research, I found that I cannot forward port by any mean, so the last option is to use Tail Scale, and so far one of the requirements broke. But, it is not my mistake, I cannot control my ISB behavior so. I have to use Tail Scale.&lt;/p&gt;

&lt;p&gt;So, we don't need DuckDNS now let's remove the &lt;code&gt;cron&lt;/code&gt; and wireguard.&lt;br&gt;
If you followed along, then you will feel what wasting time looks like.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;crontab &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; ~/duckdns
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl stop wg-quick@wg0
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl disable wg-quick@wg0
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt purge wireguard wireguard-tools &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt autoremove &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;span class="nb"&gt;sudo rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /etc/wireguard

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

&lt;/div&gt;



&lt;p&gt;Then remove that port forward line from &lt;code&gt;sudo nano /etc/sysctl.conf&lt;/code&gt;&lt;br&gt;
Now, create an account at &lt;a href="https://login.tailscale.com" rel="noopener noreferrer"&gt;https://login.tailscale.com&lt;/a&gt;&lt;br&gt;
Then add the devices and install it on Pi,&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;-fsSL&lt;/span&gt; https://tailscale.com/install.sh | sh
&lt;span class="nb"&gt;sudo &lt;/span&gt;tailscale up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and done online.&lt;br&gt;
You can check it on tailscale dashboard.&lt;/p&gt;

&lt;p&gt;Now, we can focus on building online Pi is on local and online.&lt;br&gt;
Just run a server running and good to go.&lt;/p&gt;

</description>
      <category>learning</category>
      <category>homelab</category>
      <category>networking</category>
      <category>midnightchallenge</category>
    </item>
    <item>
      <title>Homelabing interesting enough to say but why</title>
      <dc:creator>Priyanshu Verma</dc:creator>
      <pubDate>Thu, 25 Dec 2025 12:06:15 +0000</pubDate>
      <link>https://dev.to/priyanshuverma/homelabing-interesting-enough-to-say-but-why-2fhh</link>
      <guid>https://dev.to/priyanshuverma/homelabing-interesting-enough-to-say-but-why-2fhh</guid>
      <description>&lt;p&gt;So far, I tried to not tie myself to big techs for some basic stuff. Like, from starting I switched products for password management, media, IOT management. But stuck with vendor lock and tied to subscriptions and limited control. &lt;br&gt;
Finally, decided to make a home server. &lt;br&gt;
For me, it is not like buying a big rag, Plenty of storage, RAM, and heavy suite like proxmox or other. I started very small from a Raspberry Zero 2W. Why, because &lt;del&gt;money&lt;/del&gt; I am a &lt;strong&gt;professional&lt;/strong&gt; developer, I know to build a system that works in limited resources. This is not a bug but a feature. I will try to build tech from scratch that I can run on it. For Media and other IOT stuff. &lt;br&gt;
Also, This is only for my use, I am not building a robust system for millions of users using simultaneously, It is for me only or my family.&lt;/p&gt;

&lt;p&gt;This homelabing series is going to be technical and not for production systems. I don't care if I fry my Pi, it is just a learning journey, I might upgrade hardware in the future. We can start with Pi only.&lt;/p&gt;

&lt;p&gt;For more context let me tell you what is my ground for now.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Raspberry Pi Zero 2W Board (&lt;a href="https://www.raspberrypi.com/products/raspberry-pi-zero-2-w/" rel="noopener noreferrer"&gt;ORIGNAL&lt;/a&gt;)

&lt;ul&gt;
&lt;li&gt;1GHz quad-core 64-bit Arm Cortex-A53 CPU&lt;/li&gt;
&lt;li&gt;512MB SDRAM&lt;/li&gt;
&lt;li&gt;2.4GHz 802.11 b/g/n wireless LAN&lt;/li&gt;
&lt;li&gt;Bluetooth 4.2, Bluetooth Low Energy (BLE), onboard antenna&lt;/li&gt;
&lt;li&gt;Mini HDMI® port and micro USB On-The-Go (OTG) port&lt;/li&gt;
&lt;li&gt;microSD card slot&lt;/li&gt;
&lt;li&gt;HAT-compatible 40-pin header footprint (unpopulated)&lt;/li&gt;
&lt;li&gt;Micro USB power&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;SAMSUNG POWER Prime 256 GB Micro SDXC Class 10 Memory Card

&lt;ul&gt;
&lt;li&gt;capacity: 256 GB&lt;/li&gt;
&lt;li&gt;Read Speed: 160 MB/s&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Power Adapter normal 2A for Powering Pi&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's the ground I have installed Ubuntu 64bit lite on memory card and setup Pi with a static IP from home router using it's Mac Address.&lt;br&gt;
So far, nothing is installed, and I can ssh into Pi from my PC that is the bare minimum. Also, One more thing is There are two partitions I have divided unusable ~235GB of storage in ~200GB + rest. So I can deploy stuff on rest part which is ~35GB and can keep the media and all other stuff in that ~200GB part. Safe and simple. &lt;br&gt;
Also, I have installed Samba and did setup so I can mount big 200GB part to my Windows PC and store files. It is easy no big deal.&lt;/p&gt;

&lt;p&gt;This is the final ground from where I will be making it The way I want, which includes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Simple IOT controlling Dashboard for remotely switching lights at home and other fun stuff.&lt;/li&gt;
&lt;li&gt;host simple images and videos downloaded and store, no processing or indexing simple static serving. &lt;/li&gt;
&lt;li&gt;Simple authentication so, I can restrict certain things and add my family members to access media.&lt;/li&gt;
&lt;li&gt;Do it in a way so I can add more stuff in future like internal messaging or calling.
These are basic enough right, remember we will be doing it under usable 416M ram.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I do have some rules that I will follow. I don't want to mess things by using software that I feel is not giving me control and heavy on the system.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;NO cloud platform for processing or intercepting traffic like Cloudflare tunnel &lt;/li&gt;
&lt;li&gt;No REACT, for building frontend.&lt;/li&gt;
&lt;li&gt;Keep it accessible on remote location, (aka open to use even I am not connected to home network).&lt;/li&gt;
&lt;li&gt;less latency&lt;/li&gt;
&lt;li&gt;Easy to use for non-techy people.&lt;/li&gt;
&lt;li&gt;SECURED!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sounds crazy, but it is doable.&lt;br&gt;
Let's see how it goes…&lt;/p&gt;

</description>
      <category>learning</category>
      <category>homelab</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>You Want a Future in Tech? Stop Building Templates.</title>
      <dc:creator>Priyanshu Verma</dc:creator>
      <pubDate>Tue, 25 Nov 2025 16:33:30 +0000</pubDate>
      <link>https://dev.to/priyanshuverma/you-want-a-future-in-tech-stop-building-templates-4nil</link>
      <guid>https://dev.to/priyanshuverma/you-want-a-future-in-tech-stop-building-templates-4nil</guid>
      <description>&lt;p&gt;Hi&lt;br&gt;
So, Now everything around us has some sort of AI badge. Even on my Washing Machine. Seriously, Now it recommends me to select the mode based on my route. &lt;br&gt;
Let me give you a brief introduction about me. I am a developer who works major in Web. And with AI now, I am able to make beautiful UIs in seconds and write code build my side projects in Hours. I just need a prompt and some &lt;code&gt;&amp;lt;TAB&amp;gt;&lt;/code&gt; &lt;code&gt;&amp;lt;TAB&amp;gt;&lt;/code&gt;.&lt;br&gt;
Done.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I wrote this article
&lt;/h2&gt;

&lt;p&gt;If we see it from managing or productive side then it is awesome. You are now able to do Hours of work in minutes. If you are in cooperate or have a job then It fits in very awesome way. &lt;br&gt;
But, if it is easy then anyone can do it. &lt;br&gt;
I observed that &lt;strong&gt;WEB DEVELOPMENT&lt;/strong&gt; is not a hard thing anymore any one that know what to build can make websites.&lt;br&gt;
Well. Now you say building UI with AI is nothing main thing is managing it, sustaining it. I know that. I am not saying any non tech can build or sustain it. I am talking about the competition. Already the competition in Web Development is very high very other person is build an &lt;strong&gt;AI SaaS&lt;/strong&gt; for nothing. &lt;br&gt;
And I think, Now companies and Startups don't need a lot of people for Web Development and which means less Jobs and less opportunities as most of the work is simple. &lt;/p&gt;

&lt;p&gt;As a student or person who want to get in tech or want to learn something to earn money in long term. The path of learning about Web Development not looks safe anymore. &lt;/p&gt;

&lt;h2&gt;
  
  
  What is the future of Web development
&lt;/h2&gt;

&lt;p&gt;If we see the growth of AI and the tools that are available right now like we have IDEs AI integrated and some generic packages or libraries which works very fine with AI like if We need the world of web and intelligence if AI we can conclude at using tech like&lt;a href="https://ui.shadcn.com/" rel="noopener noreferrer"&gt;shadcn/ui&lt;/a&gt; and &lt;a href="https://www.better-auth.com/" rel="noopener noreferrer"&gt;Better Auth&lt;/a&gt; for authentication also for backend serverless functions, ORMs like &lt;a href="https://www.prisma.io/" rel="noopener noreferrer"&gt;Prisma&lt;/a&gt; helps to build any product very easily Everything is open and works fine with AI. Famous AI models knows about these technologies and they work very effectively on these. &lt;/p&gt;

&lt;p&gt;And in future it will get more better because almost 90% of the code of any website is open and there is a lot of data on which AI models can be trained. Every open-source frameworks, public tutorials, GitHub repos, countless blog posts, StackOverflow questions, boilerplates, templates, and design systems are public by default. And the feedback loop of the web makes things even easier for AI. If you write HTML or React, you instantly see the result. If something breaks, the browser reports the exact line.&lt;/p&gt;

&lt;p&gt;AI eating this domain of tech very rapidly.&lt;/p&gt;

&lt;h2&gt;
  
  
  What do learn then
&lt;/h2&gt;

&lt;p&gt;Before answering this question I want to ask why you get in tech. The problem with today's generation is that they think I will get in tech build websites and earn money. You and I we both know that the most easiest job in tech is to build websites and people choose it because it is simple. &lt;br&gt;
The harsh truth is people became lazy and they want instant feedbacks that's why nowadays we don't see any projects like Linux, Git or some revolutionary tech because they are depended on AI. and AI knows Web better so defaults to it. &lt;/p&gt;

&lt;p&gt;So, What to do uh? what should i learn. The answer is very simple do what AI cannot do. Programming is not dead. The humours are faking it. AI is not able to build a native app for windows, android, It is not able to build custom software for specific hardware, it cannot do cyber security. Literary it fails to code in system languages like C, C++, or Rust, Even in kotlin. You know why because the information build about these is less and building a solution for hardware or building an native app or doing cyber security stuff needs on demand actions that AI cannot replicate. Fields like DevOps AI cannot replace as it needs to work on demand according to external stimuli.  &lt;/p&gt;

&lt;h2&gt;
  
  
  What is the point of building native
&lt;/h2&gt;

&lt;p&gt;So, my friend why you should build a mobile app with native tech you can use JavaScript to build it. &lt;br&gt;
Technically it works. It shows a screen, buttons click, cool. But then I’m like… bro look at our devices. We literally have super powerful chips now, like phones with GPUs that are better than old consoles, laptops with crazy CPUs, RAM is cheap, SSD is fast… and still I open 20 chrome tabs and the whole thing starts dying. I run a game on my RTX and it can’t even stay on 60 FPS. Why? Why are games 150GB now? Why is a simple chat app using 700MB RAM?&lt;/p&gt;

&lt;p&gt;And the sad part is we all kinda became lazy. We just accept it. No one wants to build their own game engine because “eh too much work.” No one wants to create their own UI library because “just npm install something.” Everything is off-the-shelf now. Zero originality. Every website looks copy-paste same. Every game feels same. Every app has that same template vibe. We’re not optimizing, we’re just piling more stuff on top.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can AI really Replace you
&lt;/h2&gt;

&lt;p&gt;See, It depends on your skills.&lt;br&gt;
Honestly… depends on what you’re doing. Like, seriously. If your whole skillset is just copying templates, building basic CRUD, making landing pages, doing the same loops everyone is doing, then yeah AI is on your heels. Because AI is literally trained on that stuff. It has seen millions of those patterns.&lt;/p&gt;

&lt;p&gt;But the funny thing is the stuff I talked about above the messy parts, AI can’t touch that. It just can’t. It doesn’t know how to handle real hardware problems, memory issues, native bugs, performance tuning, cybersecurity attacks, networking glitches, weird OS behavior. That stuff is too real. Too unpredictable. Too out of the training data bubble. Only humans can deal with it.&lt;/p&gt;

&lt;p&gt;And this whole “recession because of AI” panic? Bro, half of it is just people sitting in their comfort zone. They open VS Code, type two prompts into an AI agent, feel like a CEO for a minute, and then scroll reels for half an hour. Then they wonder why they’re not growing and blame AI like it’s hunting them personally. It’s not AI. It’s the fact that we all got a bit too comfortable building comfort zone software.&lt;/p&gt;

&lt;p&gt;AI is not replacing the people who actually touch the real stuff the complex systems, the deep logic, the broken pipelines, the debugging nightmares, the places where you can’t just hallucinate a solution. AI is replacing the lazy, repetitive parts, the factory style coding that didn’t need a human in the first place.&lt;/p&gt;

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

&lt;p&gt;At the end of the day it’s actually not that deep.&lt;br&gt;
You wanna stay irreplaceable?&lt;br&gt;
Just stop doing the bare minimum and calling it a “skill.”&lt;br&gt;
Get out of the comfort zone stuff.&lt;br&gt;
Start touching the parts of tech where AI straight up falls on its face.&lt;br&gt;
Systems, hardware, native, security, actual optimisation is the real engineering side of things.&lt;/p&gt;

&lt;p&gt;That’s literally the whole game.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
    <item>
      <title>Self-Hosting a Password Manager on a Pi Zero 2W</title>
      <dc:creator>Priyanshu Verma</dc:creator>
      <pubDate>Sun, 28 Sep 2025 06:37:37 +0000</pubDate>
      <link>https://dev.to/priyanshuverma/self-hosting-a-password-manager-on-a-pi-zero-2w-1c79</link>
      <guid>https://dev.to/priyanshuverma/self-hosting-a-password-manager-on-a-pi-zero-2w-1c79</guid>
      <description>&lt;p&gt;As a developer and tinkerer, I love taking control of my digital environment. This weekend, I decided to host my own password manager. My goal was simple: &lt;strong&gt;keep all my sensitive data private&lt;/strong&gt;, accessible from multiple devices, while learning more about self-hosting, TLS, reverse proxies, and Docker on a low-power device. Here’s how the journey unfolded, along with problems I faced and solutions I discovered.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Choosing the Right Tool&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;I started by exploring the options. Cloud-based managers like 1Password or Bitwarden are convenient, but I wanted full control. Among self-hosted options, &lt;strong&gt;Vaultwarden&lt;/strong&gt; stood out. It’s a lightweight, unofficial Bitwarden implementation, supports TOTP, and can run on low-resource devices like a Pi Zero 2W.&lt;/p&gt;

&lt;p&gt;For a solo developer like me, Vaultwarden was ideal: small footprint, actively maintained, and feature-rich.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Step 1: Preparing the Pi&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;I installed &lt;strong&gt;Ubuntu&lt;/strong&gt; on the Pi Zero 2W and set up SSH access to manage it remotely. Since I planned to use Docker, I made sure the system was updated and installed &lt;code&gt;docker&lt;/code&gt; and &lt;code&gt;docker-compose&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After verifying Docker installation with &lt;code&gt;docker --version&lt;/code&gt;, I was ready to pull Vaultwarden.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Step 2: Running Vaultwarden in Docker&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;My first attempt to run Vaultwarden showed an important warning:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;No persistent volume!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This meant that if the container stopped or was updated, all data would be lost. Lesson one: &lt;strong&gt;always map persistent volumes&lt;/strong&gt;. I created a &lt;code&gt;vw-data&lt;/code&gt; directory and updated &lt;code&gt;docker-compose.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;vaultwarden&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vaultwarden/server:latest&lt;/span&gt;
  &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vaultwarden&lt;/span&gt;
  &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
  &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;ADMIN_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;changeme"&lt;/span&gt;
    &lt;span class="na"&gt;ROCKET_WORKERS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;ROCKET_PROXY_PATH&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/pass"&lt;/span&gt;
  &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./vw-data:/data&lt;/span&gt;
  &lt;span class="na"&gt;expose&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;80"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;ROCKET_PROXY_PATH="/pass"&lt;/code&gt; was critical.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Step 3: Subpath vs Subdomain&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;At this stage, I faced a design choice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Option 1: Subdomain&lt;/strong&gt; (&lt;code&gt;vault.mydomain.com&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Option 2: Subpath&lt;/strong&gt; (&lt;code&gt;mydomain.com/pass&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Initially, subdomains seemed neat and clean. But there are trade-offs for self-hosted services:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Certificate complexity&lt;/strong&gt;: With a subdomain, I would need a separate certificate for &lt;code&gt;vault.mydomain.com&lt;/code&gt;. With a local or internal CA, managing multiple subdomains could get messy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Future services&lt;/strong&gt;: I wanted to host other tools (like a personal wiki or file server). Using a subdomain for every service could clutter DNS and complicate VPN/local routing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tailscale &amp;amp; mobile access&lt;/strong&gt;: VPN solutions sometimes resolve only the main hostname. Subdomains occasionally fail or require additional DNS tweaks.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A &lt;strong&gt;subpath&lt;/strong&gt; approach (&lt;code&gt;/pass&lt;/code&gt;) solved these issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One certificate covers the main domain.&lt;/li&gt;
&lt;li&gt;Reverse proxy handles routing internally to different services.&lt;/li&gt;
&lt;li&gt;Makes scaling to multiple services simpler without touching DNS or VPN settings.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hence, I chose &lt;code&gt;/pass&lt;/code&gt; for Vaultwarden and left &lt;code&gt;/&lt;/code&gt; free for other services. This required careful reverse proxy configuration, which I’ll describe next.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Step 4: Reverse Proxy with Caddy&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;I used &lt;strong&gt;Caddy&lt;/strong&gt; as a reverse proxy to handle HTTPS and route &lt;code&gt;/pass&lt;/code&gt; to Vaultwarden. My first attempt was basic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;panda.local {
    tls internal
    encode zstd gzip
    reverse_proxy vaultwarden:80
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Problems immediately appeared: assets broke, WebSockets failed, and trailing slashes caused the interface to misbehave. Vaultwarden expects requests at the root, so a simple proxy was insufficient.&lt;/p&gt;

&lt;p&gt;After research and testing, I implemented:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;handle_path /pass/* {
    reverse_proxy vaultwarden:80 {
        header_up X-Real-IP {remote_host}
        header_up X-Forwarded-Proto {scheme}
        header_up X-Forwarded-Host {host}
        header_up X-Forwarded-For {remote_host}
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;handle_path /pass/*&lt;/code&gt; &lt;strong&gt;strips the &lt;code&gt;/pass&lt;/code&gt; prefix&lt;/strong&gt; before forwarding requests to Vaultwarden. This solved:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Asset loading issues&lt;/li&gt;
&lt;li&gt;WebSocket failures&lt;/li&gt;
&lt;li&gt;Trailing slash inconsistencies&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Step 5: TLS and Certificates&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Since I wanted both desktop and mobile apps to trust my self-signed setup, I used &lt;strong&gt;mkcert&lt;/strong&gt; to generate a local CA and certificates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mkcert panda.local
mkcert pass.local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copying the root CA to my desktop required careful path handling due to spaces in usernames, and mobile installation required converting &lt;code&gt;.pem&lt;/code&gt; to &lt;code&gt;.crt&lt;/code&gt; and manually trusting the certificate. Once done, browsers and apps stopped showing SSL warnings.&lt;/p&gt;

&lt;p&gt;Lesson learned: TLS is critical, but self-hosting means &lt;strong&gt;you need to manage trust explicitly&lt;/strong&gt; on each device.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Step 6: Remote Access with VPN&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;I didn’t want to open my home network to the internet. Using a VPN-like solution, I could access Vaultwarden remotely without exposing ports. Initially, there were DNS resolution issues with subdomains, but after adding entries to local hosts and configuring certificates correctly, remote access worked smoothly.&lt;/p&gt;

&lt;p&gt;This setup also allowed me to think ahead: by using &lt;code&gt;/pass&lt;/code&gt;, I left the root path free for future services, creating a small personal service ecosystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Step 7: Troubleshooting Common Issues&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Here’s a list of the main problems I faced and how I solved them:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;No persistent volume&lt;/strong&gt;: Fixed by mapping &lt;code&gt;./vw-data:/data&lt;/code&gt; in Docker Compose.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subpath asset/WebSocket issues&lt;/strong&gt;: Resolved with &lt;code&gt;handle_path /pass/*&lt;/code&gt; in Caddy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSL warnings&lt;/strong&gt;: Generated local CA with mkcert, imported into desktop and mobile devices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trailing slash problems&lt;/strong&gt;: Also handled by &lt;code&gt;handle_path&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Remote access quirks&lt;/strong&gt;: Fixed via local DNS entries and correct certificate paths.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subdomain vs subpath confusion&lt;/strong&gt;: Choosing subpath simplified certificates and routing for multiple services.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Step 8: Final Setup&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;By the end of the day, I had:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vaultwarden running under &lt;code&gt;/pass&lt;/code&gt; on the Pi Zero 2W&lt;/li&gt;
&lt;li&gt;Full HTTPS support trusted on desktop and mobile&lt;/li&gt;
&lt;li&gt;Remote access without exposing home network ports&lt;/li&gt;
&lt;li&gt;Persistent storage for all passwords&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Testing everything — creating accounts, logging in from mobile apps, syncing TOTP codes — everything worked flawlessly.&lt;/p&gt;

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

&lt;p&gt;Self-hosting is rewarding, but it comes with challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker volumes prevent accidental data loss.&lt;/li&gt;
&lt;li&gt;Reverse proxies can make or break subpath hosting.&lt;/li&gt;
&lt;li&gt;TLS and certificates are critical; trust must be manually managed for internal or mobile clients.&lt;/li&gt;
&lt;li&gt;Subpath routing simplifies multi-service hosting, while subdomains require additional DNS and cert management.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Small fixes like &lt;code&gt;handle_path&lt;/code&gt; or importing a CA may seem trivial, but they &lt;strong&gt;make the difference between a broken interface and a smooth user experience&lt;/strong&gt;.&lt;/p&gt;

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

&lt;p&gt;Self-hosting Vaultwarden on a Pi Zero 2W might seem overkill for a single user, but for me, it was about &lt;strong&gt;control, privacy, and learning&lt;/strong&gt;. The Pi handled everything surprisingly well, and Vaultwarden proved to be a solid, lightweight solution.&lt;/p&gt;

&lt;p&gt;For developers looking to take control of their digital lives: start small, expect roadblocks, and treat each error as a learning opportunity. In the end, there’s immense satisfaction in seeing your own system, from certificates to WebSockets, working exactly the way you designed it.&lt;/p&gt;

</description>
      <category>devlog</category>
      <category>learning</category>
      <category>linux</category>
      <category>docker</category>
    </item>
    <item>
      <title>Ever wondered why Windows or Android updates are so huge? This isn’t just about code – it’s about an entire hidden world of engineering farms, power consumption, and logistics. My new article opens that black box.</title>
      <dc:creator>Priyanshu Verma</dc:creator>
      <pubDate>Sun, 17 Aug 2025 10:47:14 +0000</pubDate>
      <link>https://dev.to/priyanshuverma/ever-wondered-why-windows-or-android-updates-are-so-huge-this-isnt-just-about-code-its-about-1gk</link>
      <guid>https://dev.to/priyanshuverma/ever-wondered-why-windows-or-android-updates-are-so-huge-this-isnt-just-about-code-its-about-1gk</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/priyanshuverma" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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%2Fuser%2Fprofile_image%2F994703%2F071b4abb-44c9-4685-aa5a-04f98019e345.png" alt="priyanshuverma"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/priyanshuverma/the-hidden-engineering-behind-building-massive-software-images-6j6" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;The Hidden Engineering Behind Building Massive Software Images&lt;/h2&gt;
      &lt;h3&gt;Priyanshu Verma ・ Aug 17 '25&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#programming&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#cloud&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#architecture&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#learning&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>programming</category>
      <category>bts</category>
      <category>ai</category>
    </item>
    <item>
      <title>The Hidden Engineering Behind Building Massive Software Images</title>
      <dc:creator>Priyanshu Verma</dc:creator>
      <pubDate>Sun, 17 Aug 2025 10:46:09 +0000</pubDate>
      <link>https://dev.to/priyanshuverma/the-hidden-engineering-behind-building-massive-software-images-6j6</link>
      <guid>https://dev.to/priyanshuverma/the-hidden-engineering-behind-building-massive-software-images-6j6</guid>
      <description>&lt;p&gt;Hi,&lt;br&gt;
You guys know me I try doing something new always so, recently When I first stared at the AOSP tree and saw the download size, I thought someone was pranking me. Hundreds of gigabytes? Thousands of repos? How could anyone reasonably &lt;em&gt;build&lt;/em&gt; that on a laptop, even if it had more cores than a nuclear reactor? The truth pulled me down a rabbit hole I didn’t expect — one that rewrites what “writing software” even means.&lt;/p&gt;

&lt;p&gt;Let me take you on a short film of how a piece of code becomes a massive, signed, tested, shippable image — whether that image is your phone’s system update, a Windows release, or a billion-dollar AAA game. This isn’t just about compilers and &lt;code&gt;make&lt;/code&gt;; it’s about orchestration, scale, people and machines working together in a choreography most users never see.&lt;/p&gt;




&lt;p&gt;I want you to imagine two scenes.&lt;/p&gt;

&lt;p&gt;Scene one: a lone engineer, late at night, running &lt;code&gt;make&lt;/code&gt; on a workstation. The machine hums. The screen scrolls error messages and warnings. The coffee goes cold. This image is still real in small projects, but it is increasingly a nostalgic relic.&lt;/p&gt;

&lt;p&gt;Scene two: a humming build farm, rack after rack of machines, jobs queued and parallelized across continents, caches consulted in milliseconds, thousands of tests flaring green or red. Keys and signatures are applied in a secure enclave. An image rolls down the pipeline and — eventually — reaches a device on a user’s desk via an OTA update. That is the new reality.&lt;/p&gt;

&lt;p&gt;Why the chasm between these two scenes? Why can’t we just “compile the code” and be done?&lt;/p&gt;

&lt;p&gt;It starts with scale. Modern operating systems and flagship apps aren’t a few thousand files stitched together. They’re an orchestra of components: kernels, drivers, vendor binaries, runtime engines, media libraries, UIs, services, apps, localization packs, and every test harness you can imagine. Where a small embedded project might be measured in thousands of lines, Windows and Android live in the tens-of-millions-of-lines regime. Chrome, Android, and game engines bring along enormous native code, Java or managed runtimes, and gigantic asset pipelines. Each of these pieces has its own build steps, expectations, and quirks.&lt;/p&gt;

&lt;p&gt;But scale alone doesn’t explain the orchestration required. Building a modern image is not just compiling source; it’s a multi-stage process that touches toolchains, packaging systems, signing infrastructure, artifact storage, and certification systems. You don’t merely turn C into binaries; you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;run code generators and preprocessors,&lt;/li&gt;
&lt;li&gt;produce architecture-specific binaries (x86_64, arm64, etc.),&lt;/li&gt;
&lt;li&gt;link enormous binaries (link time optimization and profile-guided optimization can be highly sequential and heavy),&lt;/li&gt;
&lt;li&gt;bundle resources (localization, images, precompiled shaders),&lt;/li&gt;
&lt;li&gt;compress and sign artifacts with secure keys,&lt;/li&gt;
&lt;li&gt;and then subject them to thousands of automated tests on real hardware.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of that introduces latency and makes naive parallelism insufficient. Even on a machine with 64 cores, disk IO, linking, and serialized packaging steps become chokepoints. The first full build, the “clean build,” necessarily touches everything: read tens of thousands of files, compile, link, pack. That’s expensive in time and in energy.&lt;/p&gt;

&lt;p&gt;Which brings me to a second, often-overlooked consequence: the environmental cost. When you multiply full builds by dozens of devs, nightly images, pull-request validations, and continuous fuzzing runs, the energy footprint becomes non-trivial. Companies running nightly images and large CI matrices are effectively operating mini data centers. This reality has pushed teams to optimize for two things: reduce redundant work and reduce waste. Caching (ccache, remote action caches), incremental builds, and smarter CI orchestration are not just developer conveniences — they’re carbon optimizations.&lt;/p&gt;

&lt;p&gt;So, how do teams cope? How does any sane engineering organization ship anything at all?&lt;/p&gt;

&lt;p&gt;They split the problem. Software at scale is &lt;em&gt;modularized&lt;/em&gt; and &lt;em&gt;specialized&lt;/em&gt;. Teams no longer touch the whole tree. An engineer working on the window manager builds the window manager. A kernel engineer builds the kernel. These are unit-of-work boundaries. The full single-piece build is delegated to a build farm — a distributed system of machines that can run the complete set of compilation tasks in parallel, honor dependency graphs, and cache results aggressively.&lt;/p&gt;

&lt;p&gt;Distributed build systems are at the heart of this approach. Google’s Goma (migrated to Reclient in 2025) and remote execution, Bazel’s remote execution, Microsoft’s BuildXL, and similar technologies allow compilation tasks to be farmed out, cached, and reused. Instead of each developer redoing the same heavy work, cached object files are reused across jobs and builds. The result: individual iteration latency drops from hours to minutes, and the full heavy build happens in a controlled, centralized way.&lt;/p&gt;

&lt;p&gt;But distributed builds are only part of the story. There’s also a surprising orchestration layer: artifact variants and packaging. One codebase can produce dozens — even hundreds — of artifacts. AOSP, for instance, doesn’t generate a single image; it generates system images for multiple device families, variants with different Google services or OEM customizations, boot images, vendor images, and more. Windows similarly produces many SKUs, localized images, and platform-specific packages. Games produce builds for multiple consoles, PC configurations, and packaged installers. Each variant multiplies the amount of work and the number of tests.&lt;/p&gt;

&lt;p&gt;Testing is another dimension that explodes resource needs. It is rarely acceptable anymore to ship untested large changes. Integration suites, fuzzers, UI tests, driver compatibility tests — these run on thousands of device instances, sometimes physically — and failures require reproducing on identical hardware. So the engineering pipeline must not only build; it must distribute, schedule, and record results from a massively parallel test farm.&lt;/p&gt;

&lt;p&gt;This reality created an entire discipline: build engineering and release engineering. These teams are the invisible logisticians of software. Their job is not product feature work; it’s to ensure developers can iterate quickly, builds are reproducible, artifacts are traceable and secure, and releases roll out smoothly. Reproducibility is a central obsession: you should be able to rebuild an artifact deterministically so you can trust what went out to users and trace bugs back to a specific build. That means pinning toolchains, hermetic builds, recorded inputs, and deterministic packaging — a lot of boring-but-important work.&lt;/p&gt;

&lt;p&gt;To me, one of the most compelling stories is the contrast between eras. In the ’80s and ’90s, building an OS was something you could conceive on a single workstation. Engineers would go home and let overnight builds run. Today, building Windows or a AAA title is akin to running a rendering farm for a movie: assets measured in terabytes, precompiled shaders, baked global illumination, and platform certification pipelines. Modern AAA titles have asset pipelines that are as much a part of the build — with their own distributed render farms — as the code compilation itself. The product is rarely “code”; it’s code times assets times compatibility matrices.&lt;/p&gt;

&lt;p&gt;Windows is a vivid example. Its codebase has accreted decades of code, multiple languages, legacy interfaces, and vast driver ecosystems. Microsoft’s approach is to carve the monolith into components. Engineers iterate locally on targeted subsystems and push changes. A centralized farm, armed with sophisticated orchestrators, then runs full builds and regression suites. For Windows, the human problem isn’t “write the code”; it’s “ensure that code plays nicely with tens of thousands of hardware permutations and years of backward compatibility.” Microsoft’s build infrastructure is built to manage that complexity — not to make building trivial, but to make shipping possible and predictable.&lt;/p&gt;

&lt;p&gt;And if you’re wondering whether AI will change this equation — write code and let machines assemble everything — the answer is: AI will help, but it won’t replace the choreography. Writing code is only a shard of the whole. The pipeline, the reproducibility, the signing, the compatibility testing, the device certification, the incremental build caches, the keys and signing policies, the human coordination, the rollback strategies — these are socio-technical problems. AI can suggest changes, even generate modules, but someone still has to decide which artifacts to build, how they get tested, what gets signed, and how to remediate a failing rollout. In short, AI can be an assistant, not the orchestra conductor — at least not in the near term.&lt;/p&gt;

&lt;p&gt;If you want to dig deeper, here are a few research and reading touchpoints I keep returning to while exploring this world:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read the Bazel documentation and the philosophy of hermetic builds.&lt;/li&gt;
&lt;li&gt;Explore Google’s papers and blog posts on Goma / remote execution (they explain why distributed compilation matters).&lt;/li&gt;
&lt;li&gt;Look up BuildXL (Microsoft) and the evolution of Git Virtual File System (GVFS) for handling huge repositories.&lt;/li&gt;
&lt;li&gt;Search for the “Reproducible Builds” project — it captures why deterministic builds are so central to security and trust.&lt;/li&gt;
&lt;li&gt;Check out material on remote caching and action caches (how CI avoids doing repeated work).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I find the story irresistible because it reframes what building software means: it’s less about the solitary craft of typing functions and more about designing resilient industrial processes. The magic of a software update isn’t the few lines someone typed last week — it’s the invisible machinery that compiled, tested, signed, and safely delivered that update to millions without breaking everything else.&lt;/p&gt;

&lt;p&gt;If you’re curious, here’s one practical way to feel this under your fingers: don’t attempt a whole AOSP build yet. Instead, pick a subsystem (a kernel module, a small Android service, a game asset pipeline task), build only that module locally, replace it into a prebuilt image, and iterate. You’ll experience first-hand the dramatic speedups that modular work affords, and you’ll see why entire teams focus on making &lt;em&gt;those&lt;/em&gt; iterations as fast and reliable as possible.&lt;/p&gt;

&lt;p&gt;When people ask me what the future of software engineering looks like, I don’t see a world where developers are obsolete. I see a world where “developer” means more — you’ll need to understand not only code, but caches, CI graphs, reproducibility guarantees, artifact signing, and the economics of compute. The boring parts — the build farms, the signing policies, the orchestration — are where trust is forged. And that, I think, is a story worth telling.&lt;/p&gt;

&lt;p&gt;Thanks for reading to the end. I know you have time to waste then also checkout my &lt;a href="https://github.com/PriyanshuPz" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;— Priyanshu Verma&lt;/p&gt;

</description>
      <category>programming</category>
      <category>cloud</category>
      <category>architecture</category>
      <category>learning</category>
    </item>
    <item>
      <title>Why MindsDB is the Fastest Way to Build AI Agents Today</title>
      <dc:creator>Priyanshu Verma</dc:creator>
      <pubDate>Fri, 27 Jun 2025 10:11:25 +0000</pubDate>
      <link>https://dev.to/priyanshuverma/why-mindsdb-is-the-fastest-way-to-build-ai-agents-today-1lbo</link>
      <guid>https://dev.to/priyanshuverma/why-mindsdb-is-the-fastest-way-to-build-ai-agents-today-1lbo</guid>
      <description>&lt;p&gt;Hi,&lt;br&gt;
In an era where building AI-powered applications often feels like assembling a spaceship from scratch, I discovered a different path — &lt;a href="https://mindsdb.com" rel="noopener noreferrer"&gt;&lt;strong&gt;MindsDB&lt;/strong&gt;&lt;/a&gt;. As a developer working on &lt;a href="https://github.com/PriyanshuPz/kbnet" rel="noopener noreferrer"&gt;&lt;strong&gt;KbNet&lt;/strong&gt;&lt;/a&gt;, I needed a way to automatically generate summaries of knowledge base articles using AI. Instead of setting up complex machine learning pipelines, I used MindsDB and built a working AI flow in hours — not days.&lt;/p&gt;

&lt;p&gt;In this article, I’ll walk you through &lt;strong&gt;why MindsDB makes AI development so seamless&lt;/strong&gt;, how it compares to traditional approaches, and how I used it to power a real-world feature in my app — &lt;strong&gt;a smart summary generator based on knowledge graph traversal&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Problem Statement
&lt;/h2&gt;

&lt;p&gt;I have structured data in a database that represents a &lt;strong&gt;knowledge graph&lt;/strong&gt;. Each node represents a concept or article, and &lt;strong&gt;maps&lt;/strong&gt; are AI flows — sequences of nodes leading to the current point in the journey.&lt;/p&gt;

&lt;p&gt;Now, I wanted to build an AI Agent that, when given a &lt;strong&gt;simple prompt&lt;/strong&gt; and a &lt;strong&gt;map reference ID&lt;/strong&gt;, could:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Retrieve all nodes associated with that map.&lt;/li&gt;
&lt;li&gt;Understand the sequence or path taken to reach the current node.&lt;/li&gt;
&lt;li&gt;Generate a rich, context-aware summary — in natural language — that sounds more like a personal journal than a SQL dump.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Sounds fun, right? Except…&lt;/p&gt;
&lt;h2&gt;
  
  
  The Traditional Route — A Long Road
&lt;/h2&gt;

&lt;p&gt;If I had taken the usual route, here's what I'd be doing:&lt;/p&gt;
&lt;h3&gt;
  
  
  1. &lt;strong&gt;Backend Setup&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Start with writing code in Python, Node, or Java. Fetch nodes using raw SQL or an ORM. Serialize the data, clean it, make it usable. Basically, your app becomes a data plumber.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. &lt;strong&gt;LLM Integration&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Pick an AI provider (OpenAI, Hugging Face, etc). Write wrapper code to format prompts, manage tokens, and handle the response. Also, hello API key management and rate limits.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. &lt;strong&gt;Agent Logic&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;You now write logic to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Order the nodes by &lt;code&gt;step_index&lt;/code&gt; or &lt;code&gt;timestamp&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Stitch the context manually&lt;/li&gt;
&lt;li&gt;Format a prompt that gives the LLM just enough — but not too much — info&lt;/li&gt;
&lt;li&gt;Clean and parse the LLM’s response&lt;/li&gt;
&lt;li&gt;Retry if it fails, maybe fallback if the summary is junk&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  4. &lt;strong&gt;API Layer&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Wrap all this in a nice endpoint. Add retries, validation, timeouts, and logs for the logs that watch other logs.&lt;/p&gt;

&lt;p&gt;🕒 &lt;strong&gt;Total Time&lt;/strong&gt;: Days (even weeks, depending on coffee supply)&lt;br&gt;&lt;br&gt;
⚙️ &lt;strong&gt;Complexity&lt;/strong&gt;: High&lt;br&gt;&lt;br&gt;
🧩 &lt;strong&gt;Modularity&lt;/strong&gt;: Low. Everything’s tightly glued&lt;br&gt;&lt;br&gt;
🚧 &lt;strong&gt;Maintenance&lt;/strong&gt;: Fragile. Tweak one piece, test everything again  &lt;/p&gt;

&lt;p&gt;I’ve done it this way before. It works, but it's definitely not something you build in a weekend — unless you skip sleep and friends.&lt;/p&gt;
&lt;h2&gt;
  
  
  Enter MindsDB — Same Problem, Way Simpler
&lt;/h2&gt;

&lt;p&gt;Now here’s where MindsDB shines. Instead of juggling a dozen moving parts, I was able to handle &lt;strong&gt;everything with a single SQL job&lt;/strong&gt; and an AI agent declaration.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Agent in One Command
&lt;/h3&gt;

&lt;p&gt;Here’s the entire setup to create the &lt;strong&gt;AI Agent&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;AGENT&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;summary_agent&lt;/span&gt;
&lt;span class="k"&gt;USING&lt;/span&gt;
  &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'gemini-2.0-flash'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;google_api_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'your_key_here'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;include_knowledge_bases&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'kbnet_kb'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="n"&gt;include_tables&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'db.maps'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'db.nodes'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'db.navigation_steps'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'db.node_relationships'&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="n"&gt;prompt_template&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'...long descriptive prompt...'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;/div&gt;



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

&lt;p&gt;This agent now understands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The map structure&lt;/li&gt;
&lt;li&gt;The nodes the user has explored&lt;/li&gt;
&lt;li&gt;The steps they’ve taken&lt;/li&gt;
&lt;li&gt;And it generates a journal-style narrative of their journey
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s declarative. You don’t write logic — you &lt;strong&gt;explain the data and intent&lt;/strong&gt;, and MindsDB takes over.&lt;/p&gt;

&lt;h3&gt;
  
  
  The System Prompt (What the Agent “Knows”)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
"You are writing a reflective, journal-style narrative of a user's learning journey through a dynamic map of interconnected topics.

You have access to the sequence of topics, summaries, and actions taken (e.g., deeper, related, similar, backtracking).
(db.maps) all the user maps has [map_id]
(db.nodes) all the nodes has [summary]
(db.navigation_steps) steps taken by user has source and target [node_id]
(db.node_relationships) relationships between nodes

Reconstruct the journey as a first-person story. Make it immersive, curious, and human. Use topic connections and user direction to build a narrative arc."

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

&lt;/div&gt;



&lt;p&gt;That’s all. The rest — connecting the dots, generating the response — is handled internally by MindsDB.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Job That Ties It Together
&lt;/h3&gt;

&lt;p&gt;I created a scheduled &lt;strong&gt;job&lt;/strong&gt; in SQL that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Picks a pending summary request.&lt;/li&gt;
&lt;li&gt;Sends it to the agent.&lt;/li&gt;
&lt;li&gt;Stores the final summary and updates the status.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;JOB&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;summary_job&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;map_summaries&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'IN_PROGRESS'&lt;/span&gt;
  &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pending_summary_view&lt;/span&gt; &lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;
  &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;map_summaries&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'COMPLETED'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;summary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;completed_at&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;NOW&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;answer&lt;/span&gt;
      &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;summary_agent&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;
      &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;question&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pending_summary_view&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'IN_PROGRESS'&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;
      &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;question&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;question&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;
  &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;EVERY&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="n"&gt;MINUTES&lt;/span&gt;
&lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&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="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pending_summary_view&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'PENDING'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'IN_PROGRESS'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Now, every 5 minutes, MindsDB checks if there's work to do. If yes, it runs the agent, updates the database, and done.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧪 Using the Agent is Just a Query
&lt;/h2&gt;

&lt;p&gt;No API calls. No webhook hell. Just SQL.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;summary_agent&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;question&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Summarize the journey of map-id: xyz'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;That’s the whole interface. Even the &lt;code&gt;question&lt;/code&gt; field acts as the input channel.&lt;/p&gt;

&lt;h2&gt;
  
  
  💡 Why This Blew My Mind
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🔥 &lt;strong&gt;Agent logic is declarative&lt;/strong&gt; — no backend to maintain&lt;/li&gt;
&lt;li&gt;🧩 &lt;strong&gt;It scales naturally&lt;/strong&gt; — just add jobs or agents&lt;/li&gt;
&lt;li&gt;🤹 &lt;strong&gt;Switching providers is trivial&lt;/strong&gt; — change &lt;code&gt;model = 'model-name'&lt;/code&gt; and &lt;code&gt;&amp;lt;provider&amp;gt;_api_key&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;⚙️ &lt;strong&gt;It runs inside the data layer&lt;/strong&gt; — no glue code or extra microservices&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I didn’t write a backend service, and I didn’t have to babysit an LLM. I wrote SQL. That’s it.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧵 Final Thoughts
&lt;/h2&gt;

&lt;p&gt;If you're someone who’s been through the mess of building LLM agents manually — gluing APIs, syncing data, writing retry logic — you’ll appreciate the simplicity of MindsDB.&lt;/p&gt;

&lt;p&gt;It feels like what SQL should’ve always been:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Declarative data + Declarative AI = Just works.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With KbNet, this gave me a fast path to production without needing to build infra from scratch. MindsDB let me focus on what mattered — the experience — instead of the plumbing.&lt;/p&gt;

&lt;p&gt;If you're working on something that could use an AI brain without a DevOps nightmare, give MindsDB a try. I’m not being paid to say this — I just had a good time not writing boilerplate code for once.&lt;/p&gt;

&lt;p&gt;And honestly, that’s rare. Usually, the only thing AI helps me generate is more bugs.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Priyanshu Verma&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/PriyanshuPz" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.linkedin.com/in/priyanshu-verma-pz" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mindsdb</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>MindsDB Made It Easy, I Made It Hard: Building an AI-Powered Knowledge Map</title>
      <dc:creator>Priyanshu Verma</dc:creator>
      <pubDate>Mon, 23 Jun 2025 16:49:13 +0000</pubDate>
      <link>https://dev.to/priyanshuverma/mindsdb-made-it-easy-i-made-it-hard-building-an-ai-powered-knowledge-map-d0g</link>
      <guid>https://dev.to/priyanshuverma/mindsdb-made-it-easy-i-made-it-hard-building-an-ai-powered-knowledge-map-d0g</guid>
      <description>&lt;p&gt;Hi,&lt;br&gt;&lt;br&gt;
It’s been a while since I posted anything tech-related. So, my friends, here we have it.&lt;br&gt;&lt;br&gt;
This article is all about &lt;strong&gt;how and why I used MindsDB&lt;/strong&gt; for my next project: &lt;strong&gt;KbNet&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  First Things First: What Even Is MindsDB?
&lt;/h2&gt;

&lt;p&gt;Before I go deep into the &lt;em&gt;technical rabbit hole&lt;/em&gt;, let me quickly tell you what MindsDB is.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MindsDB&lt;/strong&gt; is this cool open-source project that makes building AI-driven applications super smooth. It basically reduces the headache of connecting a bunch of data sources and managing AI integrations in your app. &lt;/p&gt;

&lt;p&gt;So instead of writing custom adapters and creating extra packages for every new data source, MindsDB just says:&lt;br&gt;&lt;br&gt;
&lt;em&gt;"Relax, bro, I got you."&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Some features that I personally loved:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Connect multiple data sources and pipe them into a &lt;strong&gt;unified output&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Create &lt;strong&gt;pre-built AI models with prompt templates&lt;/strong&gt; (supports OpenAI, Google Gemini, and more).&lt;/li&gt;
&lt;li&gt;Run &lt;strong&gt;background jobs and triggers&lt;/strong&gt; on specific events.&lt;/li&gt;
&lt;li&gt;Create a &lt;strong&gt;knowledge base&lt;/strong&gt; with a single SQL command that handles embedding and storing automatically.&lt;/li&gt;
&lt;li&gt;And yeah… a lot more.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But you know what? The best part?&lt;br&gt;&lt;br&gt;
MindsDB is &lt;strong&gt;SQL-based&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
Everything. I repeat — everything can be done via SQL queries.&lt;br&gt;&lt;br&gt;
No SDK madness, no complex APIs.&lt;br&gt;&lt;br&gt;
(Yes, I’ll tell you why that made my life so much easier.)&lt;/p&gt;


&lt;h2&gt;
  
  
  But Wait, What’s KbNet?
&lt;/h2&gt;

&lt;p&gt;Before jumping into the MindsDB part, let me give you some context.&lt;/p&gt;
&lt;h3&gt;
  
  
  So, what is KbNet?
&lt;/h3&gt;

&lt;p&gt;In short:&lt;br&gt;&lt;br&gt;
It’s a web app (kinda game-like) that lets users explore different aspects of any topic and &lt;em&gt;do some good old serendipitous discovery&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The idea?&lt;br&gt;&lt;br&gt;
We create a &lt;strong&gt;Knowledge Base&lt;/strong&gt; and generate a &lt;strong&gt;map of nodes in a tree format&lt;/strong&gt; for any topic.&lt;br&gt;&lt;br&gt;
The cool part? You can &lt;strong&gt;swipe through these nodes&lt;/strong&gt; (yeah, swipe gestures FTW), go back in time, rethink your path, and even build a new branch from a completely different perspective.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;I honestly wish life worked this way. If I could go back in time and create a new branch, I probably wouldn’t have chosen programming. 🤣&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
    &lt;iframe src="https://www.youtube.com/embed/AZJZm--uAKg"&gt;
  &lt;/iframe&gt;

&lt;/h2&gt;
&lt;h2&gt;
  
  
  Why I Chose MindsDB (and Decided to Suffer Anyway)
&lt;/h2&gt;

&lt;p&gt;Now, I had two choices:&lt;br&gt;&lt;br&gt;
Either build this system from scratch (why though?)&lt;br&gt;&lt;br&gt;
OR&lt;br&gt;&lt;br&gt;
Use something that can handle the AI and Knowledge Base part for me.&lt;/p&gt;

&lt;p&gt;Thankfully, MindsDB came to the rescue and made the first half &lt;strong&gt;super smooth&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
So smooth that I thought — &lt;em&gt;"I can totally build this entire app in one week."&lt;/em&gt;&lt;br&gt;&lt;br&gt;
(Oh, how innocent I was.)&lt;/p&gt;

&lt;p&gt;Then, in a moment of pure genius (read: self-inflicted torture), I decided to &lt;strong&gt;not&lt;/strong&gt; use a graph database.&lt;br&gt;&lt;br&gt;
Instead, I went for a &lt;strong&gt;relational database&lt;/strong&gt; (PostgreSQL!) with &lt;strong&gt;WebSockets.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;Why?&lt;/em&gt; No idea. I probably wanted to challenge myself for no reason. (I hate past me.)&lt;/p&gt;


&lt;h2&gt;
  
  
  This Article: MindsDB Part Only
&lt;/h2&gt;

&lt;p&gt;(I’ll talk about the database side if I ever open that schema again.)&lt;/p&gt;


&lt;h2&gt;
  
  
  How I Used MindsDB in KbNet
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Key Use Cases:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create a Knowledge Base&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI agents to generate explored summaries&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Background jobs to ingest new data&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Connect to many different data sources on the fly&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The funniest part?&lt;br&gt;&lt;br&gt;
Once I wrote the initial seed file, I literally just needed to write simple SQL queries to set up &lt;em&gt;everything&lt;/em&gt; — the Knowledge Base, AI agents, jobs, data connections… all of it.&lt;/p&gt;

&lt;p&gt;And get this:&lt;br&gt;&lt;br&gt;
I didn’t even need to create a project folder. I just spun up the &lt;strong&gt;MindsDB Docker container&lt;/strong&gt; and started testing queries directly.&lt;br&gt;&lt;br&gt;
No project setup, no dependency hell. Just a container and I’m good to go.&lt;/p&gt;

&lt;p&gt;Once I had tested everything, I just wrapped my SQL queries into a file and made a simple POST request to the MindsDB API sitting inside the container.&lt;br&gt;&lt;br&gt;
Boom. Project initialized. No fuss.&lt;/p&gt;

&lt;p&gt;Here’s the magic function I used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;runMindsDBQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;mindsDBUrl&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/api/sql/query`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&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="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="na"&gt;headers&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="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&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;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`HTTP error! status: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;rawData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&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;rawData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`MindsDB error: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;rawData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error_message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transformedData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rawData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;row&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&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="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nx"&gt;rawData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;column_names&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;col&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&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;obj&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;col&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; 
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt;  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;transformedData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&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;Error during fetch:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="err"&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;br&gt;
`&lt;/p&gt;

&lt;p&gt;Yep.&lt;br&gt;&lt;br&gt;
This one function could:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Fetch from the Knowledge Base&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Trigger AI agents&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run background jobs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ingest new data&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of it.&lt;/p&gt;




&lt;h2&gt;
  
  
  MindsDB SQL Syntax is Super Simple
&lt;/h2&gt;

&lt;p&gt;The basic structure to create anything in MindsDB:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`sql&lt;/p&gt;

&lt;p&gt;[OPERATION] [RESOURCE] [name]&lt;br&gt;
{PARAMETERS}&lt;/p&gt;

&lt;p&gt;`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`sql&lt;/p&gt;

&lt;p&gt;CREATE KNOWLEDGE_BASE kbnet (...parameters...);&lt;br&gt;
DROP JOB my_job;&lt;/p&gt;

&lt;p&gt;`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To fetch data:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`sql&lt;/p&gt;

&lt;p&gt;SELECT * FROM [RESOURCE];&lt;/p&gt;

&lt;p&gt;`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The coolest thing?&lt;br&gt;&lt;br&gt;
Whether your resource is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Twitter&lt;/li&gt;
&lt;li&gt;GitHub&lt;/li&gt;
&lt;li&gt;YouTube&lt;/li&gt;
&lt;li&gt;Wed&lt;/li&gt;
&lt;li&gt;AI Models&lt;/li&gt;
&lt;li&gt;Databases&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You get the data in a &lt;strong&gt;unified SQL table format.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
No special transformers, no extra mapping.&lt;br&gt;&lt;br&gt;
Just SELECT and chill.&lt;/p&gt;




&lt;h2&gt;
  
  
  My Honest Thoughts
&lt;/h2&gt;

&lt;p&gt;MindsDB solved &lt;strong&gt;half of my problems&lt;/strong&gt; without me needing to overthink.&lt;br&gt;&lt;br&gt;
AI, Knowledge Base, Data Ingestion — all went buttery smooth.&lt;/p&gt;

&lt;p&gt;And then, of course, I decided (for absolutely no good reason) to use &lt;strong&gt;PostgreSQL instead of a graph database&lt;/strong&gt; to store the nodes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Oh, how bad could it be?"&lt;/em&gt; — Me, before designing the database schema&lt;br&gt;&lt;br&gt;
&lt;em&gt;"I have made a terrible mistake."&lt;/em&gt; — Me, after designing the database schema&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s just say… I’ll tell you about the second part of this adventure if I ever dare to reopen that schema.&lt;/p&gt;




&lt;h2&gt;
  
  
  Life Lessons
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SQL-first AI integration is a game-changer.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;MindsDB is like your overachieving friend who actually makes your life easier.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Never trust your pen and paper system designs.&lt;/strong&gt;  &lt;/p&gt;
&lt;h2&gt;
  
  
  You &lt;em&gt;will&lt;/em&gt; regret them.
&lt;/h2&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quick Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Project Repo: &lt;a href="https://github.com/PriyanshuPz/kbnet" rel="noopener noreferrer"&gt;GitHub – kbnet&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;See you next time with another mistake I’ll regret.&lt;/em&gt;&lt;br&gt;&lt;br&gt;
— &lt;em&gt;Priyanshu Verma&lt;/em&gt;&lt;/p&gt;

</description>
      <category>mindsdb</category>
      <category>ai</category>
      <category>programming</category>
      <category>opensource</category>
    </item>
    <item>
      <title>When Life Gives You Time Off Install and Configure Neovim</title>
      <dc:creator>Priyanshu Verma</dc:creator>
      <pubDate>Wed, 04 Jun 2025 09:54:47 +0000</pubDate>
      <link>https://dev.to/priyanshuverma/when-life-gives-you-time-off-install-and-configure-neovim-3gkb</link>
      <guid>https://dev.to/priyanshuverma/when-life-gives-you-time-off-install-and-configure-neovim-3gkb</guid>
      <description>&lt;p&gt;Hello. So here’s what happened. I recently found out — almost accidentally — that I had summer vacations. Not the planned kind with beaches and iced tea, but the kind that sneaks up on you and leaves you staring at the wall asking, &lt;em&gt;“Now what?”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Naturally, I had two options: waste time or waste time in a way that &lt;em&gt;looks&lt;/em&gt; productive. I chose the latter. That’s how I stumbled into setting up Neovim.&lt;/p&gt;

&lt;p&gt;If you don’t know what Neovim is… well, don’t worry, you’re probably happier that way. But if you’re curious (or just here for the chaos), let me walk you through how I went from zero to semi-obsessed with a glorified terminal text editor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Neovim? (And What Even Is It?)
&lt;/h2&gt;

&lt;p&gt;So here’s the thing — I recently started learning Go (aka Golang, aka "Google’s gift to minimalists"), and while going through a couple of tutorials, I noticed something... odd. A bunch of the devs in those videos weren’t using the usual suspects like VSCode or JetBrains. Nope. They were in &lt;em&gt;vim&lt;/em&gt;. Like, full-on terminal-only, blinking-cursor, keyboard-ninja mode.&lt;/p&gt;

&lt;p&gt;That alone didn’t convince me. But it &lt;em&gt;did&lt;/em&gt; tickle my curiosity.&lt;br&gt;&lt;br&gt;
What’s so special about this ancient-looking editor that people still use it in 2025?&lt;/p&gt;

&lt;p&gt;After a bit of Googling and Reddit lurking, I stumbled upon &lt;strong&gt;Neovim&lt;/strong&gt; — the younger, cooler cousin of Vim. Neovim promised modern features, better plugin support, async everything, and a rabbit hole so deep that it practically dares you to fall in. So obviously, I took the bait.&lt;/p&gt;

&lt;p&gt;I didn’t really need a new text editor. But I needed &lt;em&gt;something&lt;/em&gt; to justify avoiding real responsibilities during summer. Neovim seemed perfect.&lt;/p&gt;
&lt;h2&gt;
  
  
  First Encounter: A Blank Screen and an Existential Crisis
&lt;/h2&gt;

&lt;p&gt;Installing Neovim — or so I thought — was supposed to be the easy part.&lt;br&gt;&lt;br&gt;
A simple &lt;code&gt;sudo apt install neovim&lt;/code&gt;, right?&lt;br&gt;&lt;br&gt;
Well, not for me.&lt;/p&gt;

&lt;p&gt;I'm on WSL (Windows Subsystem for Linux), and when I ran:&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;apt &lt;span class="nb"&gt;install &lt;/span&gt;neovim
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I got hit with this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Package neovim is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another &lt;span class="nb"&gt;source

&lt;/span&gt;E: Package &lt;span class="s1"&gt;'neovim'&lt;/span&gt; has no installation candidate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What does this mean? Basically: &lt;em&gt;“Neovim? Never heard of it.”&lt;/em&gt;&lt;br&gt;&lt;br&gt;
Apparently, Neovim isn’t in the default Ubuntu repo on WSL. Great.&lt;/p&gt;

&lt;p&gt;So I headed over to the &lt;a href="https://github.com/neovim/neovim/blob/master/INSTALL.md" rel="noopener noreferrer"&gt;Neovim GitHub&lt;/a&gt; like any lost soul would and followed the official install steps:&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;-LO&lt;/span&gt; https://github.com/neovim/neovim/releases/latest/download/nvim-linux-x86_64.tar.gz
&lt;span class="nb"&gt;sudo rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /opt/nvim
&lt;span class="nb"&gt;sudo tar&lt;/span&gt; &lt;span class="nt"&gt;-C&lt;/span&gt; /opt &lt;span class="nt"&gt;-xzf&lt;/span&gt; nvim-linux-x86_64.tar.gz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I added it to my PATH and cleaned up:&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;rm &lt;/span&gt;nvim-linux-x86_64.tar.gz
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;&lt;span class="s2"&gt;:/opt/nvim-linux-x86_64/bin"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, I typed &lt;code&gt;neovim&lt;/code&gt; and hit Enter.&lt;/p&gt;

&lt;p&gt;...“Command not found.”&lt;/p&gt;

&lt;p&gt;Of course.&lt;/p&gt;

&lt;p&gt;Turns out, the command is actually &lt;code&gt;nvim&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
Seriously? Who decided that?&lt;/p&gt;

&lt;p&gt;Anyway — I typed &lt;code&gt;nvim&lt;/code&gt; this time, and boom — it opened.&lt;br&gt;&lt;br&gt;
Well, “opened” is generous. What I saw was a blank terminal. No UI, no buttons, not even a helpful hint. Just a blinking cursor and the haunting silence of a terminal waiting for your next move.&lt;/p&gt;

&lt;p&gt;After a deep breath and remembering that &lt;code&gt;:q&lt;/code&gt; is the exit command, I hit &lt;code&gt;i&lt;/code&gt; to go into insert mode, typed something random, hit &lt;code&gt;Esc&lt;/code&gt;, and then typed &lt;code&gt;:q&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Instead of quitting, it slapped me with this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;E162: No write since last change &lt;span class="k"&gt;for &lt;/span&gt;buffer &lt;span class="s2"&gt;"[No Name]"&lt;/span&gt;
Press ENTER or &lt;span class="nb"&gt;type command &lt;/span&gt;to &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I had no idea what that meant, but I definitely knew I didn’t like it.&lt;/p&gt;

&lt;p&gt;This is the moment I panicked.&lt;br&gt;&lt;br&gt;
And like every sane human, I Googled: &lt;strong&gt;“how to exit Vim.”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There it was — my first real Neovim lesson:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;:q!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The magic command to &lt;em&gt;force quit&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I was in.&lt;/p&gt;

&lt;p&gt;Well, technically, I was out — but you get the point.&lt;br&gt;
You're doing a &lt;em&gt;great job&lt;/em&gt; capturing the honest, fun chaos of learning Neovim. The tone and personality are strong — it’s like reading the journal of someone falling into a beautiful rabbit hole. Below is your draft enhanced for flow, clarity, and a touch of polish while preserving your voice and humor.&lt;/p&gt;
&lt;h2&gt;
  
  
  Next up: Configuring It to Make It Feel Like Home
&lt;/h2&gt;

&lt;p&gt;To configure Neovim, I stumbled upon &lt;strong&gt;&lt;a href="https://nvchad.com/docs/quickstart/install" rel="noopener noreferrer"&gt;NvChad&lt;/a&gt;&lt;/strong&gt; — mostly because I liked the name. It sounded like the kind of setup that might high-five you after a successful config. So, I pulled it in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone &lt;span class="nt"&gt;-b&lt;/span&gt; v2.0 https://github.com/NvChad/NvChad ~/.config/nvim &lt;span class="nt"&gt;--depth&lt;/span&gt; 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When I ran &lt;code&gt;nvim&lt;/code&gt;, I realized it still wasn’t globally available. So I added Neovim to my PATH and gave it a friendly nickname while I was at it:&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;echo&lt;/span&gt; &lt;span class="s1"&gt;'export PATH="$PATH:/opt/nvim-linux-x86_64/bin"'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.zshrc
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'alias vim="nvim"'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.zshrc
&lt;span class="nb"&gt;source&lt;/span&gt; ~/.zshrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now I can just type &lt;code&gt;vim&lt;/code&gt; and it opens Neovim like a charm.&lt;/p&gt;

&lt;p&gt;When NvChad launched, it brought up what looked like a package manager asking me to install a bunch of things. I pressed &lt;code&gt;i&lt;/code&gt;, and off it went — downloading plugins and setting up the vibe.&lt;/p&gt;

&lt;p&gt;Once it finished, I restarted Neovim and immediately changed the color theme. The keymap for this was refreshingly intuitive. The important thing to understand is the &lt;strong&gt;leader key&lt;/strong&gt;, which is &lt;code&gt;&amp;lt;space&amp;gt;&lt;/code&gt; by default. Pressing it in &lt;em&gt;normal mode&lt;/em&gt; (not insert!) opens up a mini keymap menu at the bottom.&lt;/p&gt;

&lt;p&gt;To change the theme:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;space&amp;gt; + t + h
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A beautiful little theme selector popped up, and I picked my favorite. Instantly, the UI felt like &lt;em&gt;mine&lt;/em&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Learning the Basics (It Feels Like a Game)
&lt;/h2&gt;

&lt;p&gt;So far, here’s what I’ve picked up about using Neovim:&lt;/p&gt;

&lt;h3&gt;
  
  
  Modes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;NORMAL&lt;/strong&gt; mode — for navigating and running commands. (&lt;code&gt;Esc&lt;/code&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;INSERT&lt;/strong&gt; mode — for writing text. (&lt;code&gt;i&lt;/code&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Movement (aka the Game Begins)
&lt;/h3&gt;

&lt;p&gt;Instead of arrow keys, Neovim encourages &lt;code&gt;hjkl&lt;/code&gt; for movement:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;h&lt;/code&gt; — left&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;j&lt;/code&gt; — down&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;k&lt;/code&gt; — up&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;l&lt;/code&gt; — right&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's weirdly satisfying. Like I’m playing a keyboard-only game.&lt;br&gt;&lt;br&gt;
(Neovim: The Roguelike Editor™?)&lt;/p&gt;

&lt;p&gt;I found this and more inside the built-in tutorial:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;:Tutor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Keymaps I Use Now
&lt;/h3&gt;

&lt;p&gt;I’ll refer to the leader key (&lt;code&gt;&amp;lt;space&amp;gt;&lt;/code&gt;) as &lt;code&gt;&amp;lt;lk&amp;gt;&lt;/code&gt; from now on.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;&amp;lt;lk&amp;gt; + h&lt;/code&gt; — open a new terminal&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;&amp;lt;Ctrl&amp;gt; + n&lt;/code&gt; — toggle file explorer&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;&amp;lt;Tab&amp;gt;&lt;/code&gt; — switch between open files&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;:w&lt;/code&gt; — save the file&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;&amp;lt;lk&amp;gt; + x&lt;/code&gt; — close currently opened file&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Inside the file explorer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;a&lt;/code&gt; — add a new file&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;r&lt;/code&gt; — rename a file&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;d&lt;/code&gt; — delete a file&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;dd&lt;/code&gt; — delete a line at the cursor&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s all starting to click. The muscle memory is slowly forming. And every time I &lt;em&gt;don’t&lt;/em&gt; reach for the mouse, I feel a tiny spark of pride.&lt;/p&gt;

&lt;h2&gt;
  
  
  Plugins and LSPs: Making It Actually Useful
&lt;/h2&gt;

&lt;p&gt;Now that I know how to move around without rage-quitting, it's time to make Neovim actually useful for coding.&lt;/p&gt;

&lt;p&gt;Here's my current plugin wishlist — essential tools to help me survive:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;✅ &lt;strong&gt;Auto format on save&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;✅ &lt;strong&gt;LSP support&lt;/strong&gt; (language servers for Go, JavaScript, etc.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;✅ &lt;strong&gt;Copilot&lt;/strong&gt; (yes, I sold my soul for AI auto-complete)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;✅ &lt;strong&gt;Time tracker&lt;/strong&gt; (for accountability and/or guilt)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;✅ &lt;strong&gt;Discord Rich Presence&lt;/strong&gt; (because I &lt;em&gt;want&lt;/em&gt; people to know I’m tweaking my dotfiles at 2 AM)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Let’s Start Adding the Essentials
&lt;/h3&gt;

&lt;p&gt;To test things out in a real-world scenario, I decided to open one of my &lt;code&gt;Next.js&lt;/code&gt; projects — it just felt right to see how Neovim behaves with an actual codebase. Navigating was simple enough: I jumped into the project directory and ran &lt;code&gt;vim&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And... boom. The interface opened — but instead of icons, I was greeted with mysterious question marks scattered across the UI. Classic font mismatch.&lt;/p&gt;

&lt;p&gt;No worries — I quickly traced the issue back to my terminal fonts not being compatible with Neovim’s fancy icon setup. The solution? &lt;a href="https://www.nerdfonts.com/#home" rel="noopener noreferrer"&gt;Nerd Fonts&lt;/a&gt;. After some browsing, I chose &lt;code&gt;0xProto Nerd Font&lt;/code&gt;, installed it, and set it as the default font in my terminal.&lt;/p&gt;

&lt;p&gt;Problem solved. The icons rendered beautifully, and Neovim suddenly felt &lt;em&gt;alive&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting Auto-Completion Working (The LSP Journey Begins)
&lt;/h3&gt;

&lt;p&gt;With my project open, I quickly noticed the lack of auto-completion — something I’d grown dependent on. No popups, no suggestions... just silence. Time to bring in the cavalry: a Language Server Protocol (LSP) for TypeScript.&lt;/p&gt;

&lt;p&gt;To get started, I needed to tweak Neovim’s configuration. I headed to my config folder — and naturally, used Neovim itself to edit it:&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; ~/.config/nvim &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; vim
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A blank screen greeted me. If you’ve followed along, you’ll know how to open the file tree (check the previous section if not). Once inside the tree, I navigated to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lua/custom/chadrc.lua
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside that file, I added:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="n"&gt;M&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plugins&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"custom.plugins"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This line tells Neovim to look for our plugin configurations in a custom file.&lt;/p&gt;

&lt;p&gt;Next, I saved the changes (&lt;code&gt;:w&lt;/code&gt; in INSERT mode) and created a new file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lua/custom/plugins.lua
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside this file, I scaffolded a basic structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;plugins&lt;/span&gt; &lt;span class="o"&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;plugins&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that the foundation was set, it was time to add the real hero: &lt;strong&gt;&lt;a href="https://github.com/neovim/nvim-lspconfig" rel="noopener noreferrer"&gt;nvim-lspconfig&lt;/a&gt;&lt;/strong&gt;. I edited &lt;code&gt;plugins.lua&lt;/code&gt; and added the following inside the &lt;code&gt;plugins&lt;/code&gt; table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"neovim/nvim-lspconfig"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"plugins.configs.lspconfig"&lt;/span&gt;
    &lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"custom.configs.lspconfig"&lt;/span&gt;
  &lt;span class="k"&gt;end&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 configuration loads the built-in LSP setup while also pointing to our custom overrides.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating Our LSP Config
&lt;/h3&gt;

&lt;p&gt;Now to wire up our actual configuration. I created a new folder and file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Folder: &lt;code&gt;lua/custom/configs&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;File: &lt;code&gt;lspconfig.lua&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(If you’re in Neovim’s file tree, you can press &lt;code&gt;&amp;lt;Ctrl&amp;gt; + n&lt;/code&gt; to open the tree, move the cursor to &lt;code&gt;custom&lt;/code&gt;, press &lt;code&gt;a&lt;/code&gt;, and type &lt;code&gt;configs/lspconfig.lua&lt;/code&gt;.)&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;lspconfig.lua&lt;/code&gt;, I wrote the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;on_attach&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"plugins.configs.lspconfig"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;on_attach&lt;/span&gt;
&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;capabilities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"plugins.configs.lspconfig"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;capabilities&lt;/span&gt;

&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;lspconfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"lspconfig"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;servers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"tsserver"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"tailwindcss"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"eslint"&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;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lsp&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;ipairs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;servers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;lspconfig&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;lsp&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;on_attach&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;on_attach&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;capabilities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sets up LSPs for TypeScript, Tailwind CSS, and ESLint. The best part? It’s extendable. I can easily plug in support for Rust or Go later by just appending to the &lt;code&gt;servers&lt;/code&gt; list.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing Language Servers with Mason
&lt;/h3&gt;

&lt;p&gt;Installing language servers manually is tedious, so I reached for &lt;a href="https://github.com/mason-org/mason.nvim" rel="noopener noreferrer"&gt;Mason.nvim&lt;/a&gt; to automate the job.&lt;/p&gt;

&lt;p&gt;Back in &lt;code&gt;plugins.lua&lt;/code&gt;, I added:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"mason-org/mason.nvim"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;opts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ensure_installed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="s2"&gt;"eslint-lsp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"prettierd"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"tailwindcss-language-server"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"typescript-language-server"&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;After saving, I relaunched Neovim and ran:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;MasonInstallAll
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Voilà! Language servers downloaded and ready to go. At this point, TypeScript and Tailwind auto-completion were working like magic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding Formatting with Prettier
&lt;/h3&gt;

&lt;p&gt;However, auto-completion alone isn’t enough — we need formatting too. Even though we had installed &lt;code&gt;prettierd&lt;/code&gt;, it wasn’t doing its job yet.&lt;/p&gt;

&lt;p&gt;Enter: &lt;strong&gt;&lt;a href="https://github.com/nvimtools/none-ls.nvim" rel="noopener noreferrer"&gt;none-ls.nvim&lt;/a&gt;&lt;/strong&gt; — the plugin that bridges formatters and linters to Neovim.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;plugins.lua&lt;/code&gt;, I added:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"nvimtools/none-ls.nvim"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"VeryLazy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;opts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"custom.configs.none-ls"&lt;/span&gt;
  &lt;span class="k"&gt;end&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;Time for one last config file. I created:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lua/custom/configs/none-ls.lua
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside it, I added:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;augroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nvim_create_augroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"LspFormatting"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;null_ls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"null-ls"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;sources&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;null_ls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;builtins&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;formatting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prettierd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="n"&gt;on_attach&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&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;bufnr&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;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;supports_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"textDocument/formatting"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
      &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nvim_clear_autocmds&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;augroup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bufnr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nvim_create_autocmd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"BufWritePre"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;augroup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bufnr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;callback&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
          &lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lsp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="n"&gt;bufnr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bufnr&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&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;opts&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This hook listens for file saves and auto-formats the code using &lt;code&gt;prettierd&lt;/code&gt;. Exactly what we need for a smooth dev experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And just like that, LSP support is fully integrated — from completion to formatting.&lt;/strong&gt; My Neovim setup just leveled up.&lt;/p&gt;

&lt;h3&gt;
  
  
  Let’s Bring in AI ✨ (and Some Visual Flair)
&lt;/h3&gt;

&lt;p&gt;Now that LSP and formatting are handled, it's time to supercharge my workflow — with AI!&lt;/p&gt;

&lt;h3&gt;
  
  
  🧠 Adding GitHub Copilot
&lt;/h3&gt;

&lt;p&gt;Integrating Copilot with Neovim is surprisingly simple. I opened up my trusty &lt;code&gt;plugins.lua&lt;/code&gt; file once again and added the following plugin definition to the list:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"github/copilot.vim"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"InsertEnter"&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 tells Neovim to lazily load Copilot the moment I enter &lt;code&gt;INSERT&lt;/code&gt; mode.&lt;/p&gt;

&lt;p&gt;After saving the file, I restarted Neovim and ran:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;Copilot setup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This initialized Copilot and connected it to GitHub. If for some reason it didn’t load automatically, I nudged it manually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;Lazy load copilot&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;vim&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just like that — Copilot was ready to start pairing with me. Smart suggestions, code completions, and a boost in productivity — unlocked!&lt;/p&gt;

&lt;h3&gt;
  
  
  Syntax Highlighting with Treesitter
&lt;/h3&gt;

&lt;p&gt;With Copilot onboard, it was time to make the editor more readable and pleasing to the eyes. For that, I turned to &lt;a href="https://tree-sitter.github.io/tree-sitter/index.html" rel="noopener noreferrer"&gt;Treesitter&lt;/a&gt; — the gold standard for syntax highlighting and parsing.&lt;/p&gt;

&lt;p&gt;Again, I popped into &lt;code&gt;plugins.lua&lt;/code&gt; and added:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"nvim-treesitter/nvim-treesitter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;opts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"plugins.configs.treesitter"&lt;/span&gt;
    &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ensure_installed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="s2"&gt;"lua"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"javascript"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"typescript"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s2"&gt;"tsx"&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;opts&lt;/span&gt;
  &lt;span class="k"&gt;end&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;I made sure to include &lt;code&gt;tsx&lt;/code&gt; for React support, and of course, you can toss in other languages like &lt;code&gt;rust&lt;/code&gt; and &lt;code&gt;go&lt;/code&gt; if your stack demands it.&lt;/p&gt;

&lt;p&gt;Now everything — from tags to braces — was beautifully color-coded and structured.&lt;/p&gt;

&lt;h3&gt;
  
  
  ⏱️ Optional (But Cool): WakaTime for Coding Analytics
&lt;/h3&gt;

&lt;p&gt;This one’s for the productivity nerds out there — like me. I love tracking how much time I actually spend coding, so I set up &lt;a href="https://wakatime.com/" rel="noopener noreferrer"&gt;WakaTime&lt;/a&gt;, which gives me detailed insights into where my time goes.&lt;/p&gt;

&lt;p&gt;To install the plugin, I added the following to (yes, again) &lt;code&gt;plugins.lua&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"wakatime/vim-wakatime"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lazy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After restarting Neovim, I simply ran:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;WakaTimeApiKey
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then pasted in my API key from the WakaTime dashboard. Boom — time tracking was live. I could now see how long I spend inside Neovim, what languages I code in the most, and when I’m most productive.&lt;/p&gt;

&lt;p&gt;With AI suggestions, beautiful syntax, and time-tracking all set up, Neovim was starting to feel less like a terminal — and more like an IDE.&lt;/p&gt;

&lt;p&gt;Here's a polished and storytelling-enhanced version of your final section. It stays faithful to your technical steps, while improving clarity and flow:&lt;/p&gt;

&lt;h3&gt;
  
  
  Final Touch: Flexing on Discord with Rich Presence
&lt;/h3&gt;

&lt;p&gt;For the final touch, I decided to bring in &lt;strong&gt;Discord Rich Presence&lt;/strong&gt; so I can subtly flex my Neovim setup to friends — because why not?&lt;/p&gt;

&lt;p&gt;After a bit of research, I learned that Discord RPC doesn't work out-of-the-box in &lt;strong&gt;WSL2&lt;/strong&gt; due to limitations in how it handles inter-process communication. It &lt;em&gt;does&lt;/em&gt; work in &lt;strong&gt;WSL1&lt;/strong&gt;, but I wanted to try getting it working in WSL2 anyway using a clever workaround.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Add the Plugin
&lt;/h3&gt;

&lt;p&gt;As always, I started by adding the plugin to my &lt;code&gt;plugins.lua&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s1"&gt;'vyfor/cord.nvim'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lazy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then opened Neovim and ran:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;Cord &lt;span class="k"&gt;update&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If it works at this point — you're golden. But like many WSL2 users, I hit a wall. So I followed &lt;a href="https://gist.github.com/mousebyte/af45cbecaf0028ea78d0c882c477644a" rel="noopener noreferrer"&gt;these instructions&lt;/a&gt; to bridge Discord from WSL to Windows.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Install Required Tools
&lt;/h3&gt;

&lt;p&gt;You'll need two pieces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://www.dest-unreach.org/socat/" rel="noopener noreferrer"&gt;&lt;code&gt;socat&lt;/code&gt;&lt;/a&gt; — for socket redirection in WSL&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/jstarks/npiperelay" rel="noopener noreferrer"&gt;&lt;code&gt;npiperelay&lt;/code&gt;&lt;/a&gt; — to communicate with Windows named pipes&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Start by installing &lt;code&gt;socat&lt;/code&gt; inside your WSL terminal:&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;apt &lt;span class="nb"&gt;install &lt;/span&gt;socat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then clone and build &lt;code&gt;npiperelay&lt;/code&gt; for Windows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/jstarks/npiperelay.git 
go &lt;span class="nb"&gt;install &lt;/span&gt;github.com/jstarks/npiperelay
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now build it for Windows and place it somewhere accessible:&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="nv"&gt;GOOS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;windows go build &lt;span class="nt"&gt;-o&lt;/span&gt; /mnt/c/Users/&amp;lt;username&amp;gt;/go/bin/npiperelay.exe github.com/jstarks/npiperelay
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Replace &lt;code&gt;&amp;lt;username&amp;gt;&lt;/code&gt; with your actual Windows username.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Create a symbolic link for convenience:&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 ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; /mnt/c/Users/&amp;lt;username&amp;gt;/go/bin/npiperelay.exe /usr/local/bin/npiperelay.exe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Hook into Your Neovim Launch
&lt;/h3&gt;

&lt;p&gt;We now need to run &lt;code&gt;socat&lt;/code&gt; and &lt;code&gt;npiperelay&lt;/code&gt; each time we launch Neovim, so I created a wrapper function in my &lt;code&gt;.bashrc&lt;/code&gt; (or &lt;code&gt;.zshrc&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;nvim&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; pidof socat &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null 2&amp;gt;&amp;amp;1&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; /tmp/discord-ipc-0 &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; /tmp/discord-ipc-0
        socat UNIX-LISTEN:/tmp/discord-ipc-0,fork &lt;span class="se"&gt;\&lt;/span&gt;
            EXEC:&lt;span class="s2"&gt;"/usr/local/bin/npiperelay.exe //./pipe/discord-ipc-0"&lt;/span&gt; 2&amp;gt;/dev/null &amp;amp;
    &lt;span class="k"&gt;fi

    if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$# &lt;/span&gt;&lt;span class="nt"&gt;-eq&lt;/span&gt; 0 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nb"&gt;command &lt;/span&gt;nvim
    &lt;span class="k"&gt;else
        &lt;/span&gt;&lt;span class="nb"&gt;command &lt;/span&gt;nvim &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures the IPC bridge is set up &lt;strong&gt;only once&lt;/strong&gt;, and works whether I run &lt;code&gt;nvim&lt;/code&gt; directly or pass it files as arguments.&lt;/p&gt;

&lt;p&gt;If you prefer, you can rename this function or alias it to something else.&lt;/p&gt;

&lt;h3&gt;
  
  
  Done!
&lt;/h3&gt;

&lt;p&gt;That’s it — a full minimal Neovim config:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;📜 Syntax highlighting&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;🤖 AI with Copilot&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;🧠 LSP and formatting support&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;⌛ Time tracking&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;🕹️ Discord Rich Presence&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now I can code with AI assistance, auto-format on save, track my hours, and flex on Discord — all within a terminal. I wasted too much time setting this up, now I'm going to eat something.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: This guide reflects my personal setup and preferences. I am not affiliated with, promoting, or endorsing any of the tools or services mentioned. Please evaluate and use them based on your own requirements and discretion.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Follow me on GitHub &lt;a href="https://github.com/PriyanshuPz" rel="noopener noreferrer"&gt;@PriyanshuPz&lt;/a&gt;&lt;/p&gt;

</description>
      <category>neovim</category>
      <category>vim</category>
      <category>beginners</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Inside a Rust-Powered HTTP Server Built From Zero</title>
      <dc:creator>Priyanshu Verma</dc:creator>
      <pubDate>Fri, 30 May 2025 13:53:09 +0000</pubDate>
      <link>https://dev.to/priyanshuverma/a-masochists-journey-to-building-an-http-server-from-scratch-1272</link>
      <guid>https://dev.to/priyanshuverma/a-masochists-journey-to-building-an-http-server-from-scratch-1272</guid>
      <description>&lt;p&gt;I've always been curious about Rust. The buzz around its memory safety, zero-cost abstractions, and fearsome compiler made me both intrigued and intimidated. Instead of starting with tutorials or relying on heavy frameworks, I decided to try something different — build a tiny server from scratch.&lt;/p&gt;

&lt;p&gt;Ah yes, because when normal people want to learn a new programming language, they start with "Hello World." But me? I thought, "Let's reinvent the wheel, but make it square, and also let's use only stone tools while we're at it."&lt;/p&gt;

&lt;p&gt;It might sound boring, or even like a waste of time (and yes, at times it felt like that), but I ended up learning a lot through the process. To take things up a notch, I decided to do it using only the standard library — no external crates.&lt;/p&gt;

&lt;p&gt;The challenge? Build a simple REST API server for a to-do app, with just the bare minimum. No &lt;code&gt;tokio&lt;/code&gt;, no &lt;code&gt;hyper&lt;/code&gt;, no &lt;code&gt;serde&lt;/code&gt;. Just Rust's &lt;code&gt;std&lt;/code&gt; library. At least, that was the plan — until things got overwhelming enough to reconsider. 😉&lt;/p&gt;

&lt;p&gt;Spoiler: By "overwhelming," I mean the moment I realized parsing JSON without &lt;code&gt;serde&lt;/code&gt; is like trying to eat soup with a fork — technically possible but an exercise in futility.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup and Getting Started
&lt;/h2&gt;

&lt;p&gt;As a professional beginner, I started by watching a crash course on Rust before diving in. Trust me, I knew nothing about Rust.&lt;/p&gt;

&lt;p&gt;"Professional beginner" is my politically correct way of saying "I have impostor syndrome but with extra steps." This way, when I inevitably mess up, I can say, "Well, what did you expect? I'm professionally bad at this!"&lt;/p&gt;

&lt;p&gt;After watching a simple crash course and learning how Rust works and what its syntax looks like, I realized for the first time — it's not going to be simple.&lt;/p&gt;

&lt;p&gt;Rust's learning curve isn't a curve at all. It's a brick wall with spikes on it, and the Rust compiler stands atop it, looking down at you with a mixture of pity and disappointment, like a cat watching you try to open a can of tuna with your bare hands.&lt;/p&gt;




&lt;h2&gt;
  
  
  DAY 1: In Which I Convince Myself I Know Rust
&lt;/h2&gt;

&lt;p&gt;Ignoring the existential dread that comes with learning a new systems programming language, I installed Rust on WSL with a simple one-liner from Rust's official site. Then created a fresh project and started printing "hello world" so I could motivate myself that I &lt;em&gt;do&lt;/em&gt; know Rust.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo new rust-server
&lt;span class="nb"&gt;cd &lt;/span&gt;rust-server
cargo run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Five minutes in, and I'm basically Jon Skeet of the Rust world. Put that on my LinkedIn.&lt;/p&gt;

&lt;p&gt;After wasting some time patting myself on the back for successfully printing text to a console (a true technological breakthrough), I opened Rust docs for the standard library and found &lt;code&gt;TcpListener&lt;/code&gt;. I quickly created a server using it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;listener&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;TcpListener&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="s"&gt;"127.0.0.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It was simple — just gave the address and unwrapped any error.&lt;/p&gt;

&lt;p&gt;It is &lt;strong&gt;not recommended to unwrap&lt;/strong&gt; any function that can give an error in production, because if an error occurs, it will panic and stop the program. Since this is &lt;strong&gt;not production code&lt;/strong&gt;, I can do it.&lt;/p&gt;

&lt;p&gt;In fact, I'll be sprinkling &lt;code&gt;unwrap()&lt;/code&gt;s like confetti throughout this project. My error handling strategy: "If it breaks, I'll deal with it... never." This is what we call "confidence" in the software development industry.&lt;/p&gt;

&lt;p&gt;After creating the listener, we need to listen for incoming requests. Here's how:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="nf"&gt;.incoming&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;handle_connection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&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;Very basic, single-threaded server that will listen for one incoming request at a time.&lt;/p&gt;

&lt;p&gt;For now, I don't think I will add multithreading (I was wrong. I did that).&lt;/p&gt;

&lt;p&gt;My famous last words. Right up there with "How hard could it be?" and "I'm sure we don't need unit tests for this."&lt;/p&gt;

&lt;p&gt;With classic beginner energy, I unwrapped the stream and called &lt;code&gt;handle_connection&lt;/code&gt; — a function I defined like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;handle_connection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TcpStream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;buf_read&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;BufReader&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;stream&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;line&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;buf_read&lt;/span&gt;&lt;span class="nf"&gt;.lines&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&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;line&lt;/span&gt;&lt;span class="nf"&gt;.is_empty&lt;/span&gt;&lt;span class="p"&gt;()&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="c1"&gt;// End of headers&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Received: {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&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;Believe me or not, printing this took serious time.&lt;/p&gt;

&lt;p&gt;By "serious time," I mean I spent 30 minutes debugging why my buffer reader wouldn't print anything, only to realize I had forgotten to actually send a request to the server. Yes, I'm that developer who checks if the monitor is plugged in after calling IT support.&lt;/p&gt;

&lt;p&gt;It's very basic — create a buffer reader and loop through each line, printing it to the console.&lt;/p&gt;

&lt;p&gt;At the end of the day, you'll see something like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Here, &lt;code&gt;mut&lt;/code&gt; is used with &lt;code&gt;&amp;amp;&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
In Rust, &lt;code&gt;mut&lt;/code&gt; is for making a variable mutable, and &lt;code&gt;&amp;amp;&lt;/code&gt; is for referencing a variable instead of copying it.&lt;br&gt;&lt;br&gt;
So, &lt;code&gt;&amp;amp;mut stream&lt;/code&gt; is a mutable reference. If you try to access or modify the stream again outside this function, you'll get an error (ownership rules!).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Did I mention Rust has ownership rules? It's like that friend who won't lend you anything without making you sign a contract in blood. "You can borrow my stream, but I need it back EXACTLY as you found it, or the compiler will hunt you down."&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Received: GET / HTTP/1.1
Received: Host: localhost:5000
Received: User-Agent: curl/8.5.0
Received: Accept: &lt;span class="k"&gt;*&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You're seeing how HTTP works. This is the &lt;a href="https://www.rfc-editor.org/rfc/rfc1945#section-3" rel="noopener noreferrer"&gt;protocol&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ah, the raw HTTP request in all its glory. It's like seeing how sausage is made—oddly satisfying but makes you appreciate the abstractions that normally hide it from you.&lt;/p&gt;

&lt;h3&gt;
  
  
  In the &lt;strong&gt;first line&lt;/strong&gt;, we have:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Method&lt;/strong&gt; – what action to perform (like GET/POST). Case-sensitive. &lt;a href="https://www.rfc-editor.org/rfc/rfc1945#section-5.1.1" rel="noopener noreferrer"&gt;RFC&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Request-URI&lt;/strong&gt; – the path. &lt;a href="https://www.rfc-editor.org/rfc/rfc1945#section-3.2" rel="noopener noreferrer"&gt;Section 3.2&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Version&lt;/strong&gt; – the HTTP version. &lt;a href="https://www.rfc-editor.org/rfc/rfc1945#section-3.1" rel="noopener noreferrer"&gt;RFC&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The rest are headers: Host, User-Agent, etc.&lt;/p&gt;

&lt;p&gt;Yes, I'm actually linking to the RFCs, which makes me feel very important. Nothing says "I'm a serious developer" like citing RFC documents that nobody is actually going to read. But they're there, just in case you want to fall asleep really quickly.&lt;/p&gt;

&lt;p&gt;If we send a POST request, we also get the body:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Received: POST / HTTP/1.1
Received: Host: localhost:5000
Received: Content-Type: application/json
Received: User-Agent: curl/8.5.0
Received: Content-Length: 21
Received: 
Received: &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"hello"&lt;/span&gt;: &lt;span class="s2"&gt;"John Doe"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For now, we need to extract:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Method&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Path&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Body&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Headers&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Query parameters&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rest is useless (for now).&lt;br&gt;&lt;br&gt;
Extracting it from this plain stream isn't easy — it's just text with no types.&lt;br&gt;&lt;br&gt;
It'll be fun to do (it won't be).&lt;/p&gt;

&lt;p&gt;Spoiler: When a developer says something will be "fun," they mean it will be a soul-crushing exercise that makes them question their career choices. But hey, at least there's coffee.&lt;/p&gt;


&lt;h3&gt;
  
  
  Sending the Response
&lt;/h3&gt;

&lt;p&gt;Right now, the request just hangs because we're not sending anything back.&lt;/p&gt;

&lt;p&gt;It's like when you text someone a question and they read it but don't respond. Rude, right? Our server is currently that person.&lt;/p&gt;

&lt;p&gt;Let's write a manual response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;status_line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"HTTP/1.1 200 OK"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;contents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"{'hello': 'World'}"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;contents&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"{status_line}&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;Content-Length: {length}&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;Content-Type: application/json&lt;/span&gt;&lt;span class="se"&gt;\r\n\r\n&lt;/span&gt;&lt;span class="s"&gt;{contents}"&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="nf"&gt;.write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="nf"&gt;.as_bytes&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Boom. Response sent.&lt;/p&gt;

&lt;p&gt;When I typed "Boom," I felt like I just launched a SpaceX rocket, but in reality, I just sent 18 bytes over localhost. Let's keep our achievements in perspective.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;HTTP/1.1 200 OK
Content-Length: 18
Content-Type: application/json

&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'hello'&lt;/span&gt;: &lt;span class="s1"&gt;'World'&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  That's It for Day 1
&lt;/h3&gt;

&lt;p&gt;That's all I did. Simple stuff — but I was happy. This bit of work taught me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;How to spin up a TCP server in Rust with only the standard library.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How HTTP requests actually look on the wire.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How to send a raw HTTP response manually.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More to come in Day 2.&lt;/p&gt;

&lt;p&gt;I ended the day feeling like I'd accomplished something significant, when in reality all I'd done was reinvent technology from the 1990s. But you know what? Sometimes you need to go back to understand how to move forward. At least that's what I tell myself to feel better about spending an entire day writing what most frameworks do in three lines of code.&lt;/p&gt;




&lt;h2&gt;
  
  
  DAY 2: HTTP Parsing Hell, or "Why Don't I Just Use a Framework Again?"
&lt;/h2&gt;

&lt;p&gt;Today's mission? Turn a chaotic stream of bytes into a neat little &lt;code&gt;Request&lt;/code&gt; struct that we can actually work with. Think of it like decoding alien signals, except it's HTTP and slightly less cool. The goal is to be able to write code like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;handle_connection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TcpStream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&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;stream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"REQUEST METHOD: {:?}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="py"&gt;.method&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;Yep, just calling &lt;code&gt;Request::new(&amp;amp;stream)&lt;/code&gt; should give us all the sweet, sweet info — method, path, headers, query, body. But before that happens, we need to teach our program how to read the stream and not choke.&lt;/p&gt;

&lt;p&gt;If you're wondering "why don't I just use a library for this?" — congratulations, you're smarter than me. But we're committed to the bit now, so let's keep reinventing this particular wheel until it's almost round-ish.&lt;/p&gt;

&lt;p&gt;So, To implement it let's create a struct named &lt;code&gt;Request&lt;/code&gt; for this I will create a new file &lt;code&gt;request/mod.rs&lt;/code&gt;. And create &lt;code&gt;lib.rs&lt;/code&gt; file in root. Inside &lt;code&gt;lib.rs&lt;/code&gt; I will register &lt;code&gt;request/mod.rs&lt;/code&gt; like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will register this module, add you will get autocompletion if using VS Code.&lt;/p&gt;

&lt;p&gt;Ah yes, autocomplete, the thing that writes 90% of my code for me. Let's be honest, without IntelliSense, most of us would be reduced to grunting and throwing rocks at our computers.&lt;/p&gt;

&lt;p&gt;Now, Inside &lt;code&gt;request/mod.rs&lt;/code&gt; let us define the struct.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[derive(Debug)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;String&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;pub&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;String&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;pub&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&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 request struct will have these stored stuff we talked in Day 1. Also, added &lt;code&gt;Debug&lt;/code&gt; macro for debugging it is optional. For this struct we need to define only one function named &lt;code&gt;new&lt;/code&gt; which will intake the &lt;code&gt;TCPStream&lt;/code&gt; reference and in result gives response or error string. &lt;br&gt;
Filename: &lt;code&gt;request/mod.rs&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ...request struct code&lt;/span&gt;
&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;stream&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;TcpStream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="c1"&gt;// processing code...&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;Like this we can create a function which is public so can be accessed by anywhere taking &lt;code&gt;TCPStream&lt;/code&gt; and resulting request. &lt;/p&gt;

&lt;p&gt;I've gone for the &lt;code&gt;Result&amp;lt;Self, String&amp;gt;&lt;/code&gt; return type because nothing says "I'm a Rust developer" quite like wrapping everything in &lt;code&gt;Result&lt;/code&gt;. It's like putting your code in bubble wrap — sure, it's harder to use, but at least it won't break if you drop it.&lt;/p&gt;

&lt;p&gt;Our &lt;strong&gt;first step&lt;/strong&gt; is to grab all the text from the buffer and store it. &lt;br&gt;
we need to read the bytes from the stream. For that, we define a couple of variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;MESSAGE_SIZE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;usize&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="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;received&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt; &lt;span class="c1"&gt;// this will store full request&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;rx_bytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0u8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;MESSAGE_SIZE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// temporary buffer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Q: Why use a fixed-size buffer like &lt;code&gt;rx_bytes&lt;/code&gt; instead of reading directly into &lt;code&gt;received&lt;/code&gt;?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A: Because &lt;code&gt;stream.read()&lt;/code&gt; wants a fixed-size buffer to read into. I spent way too much time figuring that out. Don't be like me. Just use the buffer.&lt;/p&gt;

&lt;p&gt;True story: I spent about an hour trying various combinations of &lt;code&gt;.read_to_end()&lt;/code&gt;, &lt;code&gt;.read_to_string()&lt;/code&gt;, and custom buffer strategies before realizing that TCP streams don't have a clear "end" until they're closed. The documentation mentions this, but who reads documentation, am I right? (Please read documentation.)&lt;/p&gt;

&lt;p&gt;Now the scary part: the loop.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;loop&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;bytes_read&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="nf"&gt;.read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;rx_bytes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;bytes_read&lt;/span&gt; &lt;span class="p"&gt;{&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This loop keeps reading the stream into &lt;code&gt;rx_bytes&lt;/code&gt;, and each chunk is pushed into &lt;code&gt;received&lt;/code&gt;. We stop reading once fewer bytes are read than our buffer size — usually meaning the request has ended.&lt;/p&gt;

&lt;p&gt;Also, remember: I'm just sharing my experience. If you copied this loop from Stack Overflow, check it before you run it. 😂&lt;/p&gt;

&lt;p&gt;Let's be honest, we're all copying from Stack Overflow. The difference between junior and senior developers is that seniors know which parts to modify after copying.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;bytes_read&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;received&lt;/span&gt;&lt;span class="nf"&gt;.extend_from_slice&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;rx_bytes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;bytes&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;bytes&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;MESSAGE_SIZE&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="nf"&gt;Err&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;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nd"&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="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;We are handling two condition if result is &lt;code&gt;OK&lt;/code&gt; and on &lt;code&gt;Err&lt;/code&gt;. For error, we are doing basic console logging. And For &lt;code&gt;Ok&lt;/code&gt;. We are getting a variable named &lt;code&gt;bytes&lt;/code&gt; which is a &lt;code&gt;usize&lt;/code&gt; integer that is the &lt;strong&gt;number of bytes that were successfully read&lt;/strong&gt;. Only need to convert it in string and then extract the information.&lt;/p&gt;

&lt;p&gt;The error handling here is what I call "log and pray" — we print the error and hope someone is watching the console. This is state-of-the-art error handling for weekend projects.&lt;/p&gt;

&lt;p&gt;Now, &lt;strong&gt;second step&lt;/strong&gt; is to convert this &lt;code&gt;received&lt;/code&gt; vector in string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;request_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_utf8&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;received&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows us to convert it into string. Now, will split this &lt;code&gt;request_text&lt;/code&gt; with &lt;code&gt;newline&lt;/code&gt; character. And create some &lt;code&gt;HashMap&lt;/code&gt; variables to store headers and query parameters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;request_lines&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request_text&lt;/span&gt;&lt;span class="nf"&gt;.split_inclusive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'\n'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Store headers and query parameters&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;header_map&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;HashMap&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;query_params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;HashMap&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ah, the classic "split and collect" pattern — the programming equivalent of opening a UPS package with safety scissors. It works, but there's a lot of awkward maneuvering involved.&lt;/p&gt;

&lt;p&gt;Now, let's start extracting stuff. Foremost the easy one http method which is in first time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// First line of HTTP request, e.g., "GET /path?x=1 HTTP/1.1"&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;request_line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request_lines&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="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;parts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request_line&lt;/span&gt;&lt;span class="nf"&gt;.split_ascii_whitespace&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// Extract HTTP method and full path&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;http_method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="nf"&gt;.next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;full_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="nf"&gt;.next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&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 have taken first line from the &lt;code&gt;request_lines&lt;/code&gt; vector we created. Then, split that with whitespace and assigned first part as the &lt;code&gt;http_method&lt;/code&gt; and second to &lt;code&gt;full_path&lt;/code&gt;.&lt;br&gt;
&lt;code&gt;full_path&lt;/code&gt; will have our path name and query parameters that we will extract by separating this with &lt;code&gt;?&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Notice those beautiful &lt;code&gt;.unwrap()&lt;/code&gt; calls? That's me saying "I trust this HTTP request to be perfectly formatted." Which is like trusting a toddler with cake — it's gonna get messy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Separate path and query string (e.g., "/search?q=rust")&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;path_and_query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;full_path&lt;/span&gt;&lt;span class="nf"&gt;.split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'?'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.collect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;path_and_query&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After separating the first one will always be the path and rest we will handle if the length of the &lt;code&gt;path_and_query&lt;/code&gt; is greater than 1 which means query params are passed than.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;path_and_query&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;query_string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;path_and_query&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="nf"&gt;.join&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="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;query_pairs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;query_string&lt;/span&gt;&lt;span class="nf"&gt;.split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;amp;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.collect&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;pair&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;query_pairs&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Some&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="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pair&lt;/span&gt;&lt;span class="nf"&gt;.split_once&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&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;query_params&lt;/span&gt;&lt;span class="nf"&gt;.insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="nf"&gt;.to_string&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;Further, &lt;code&gt;query_string&lt;/code&gt; is the string after joining the rest of the stuff excluding the &lt;code&gt;path&lt;/code&gt;. You can see the spreading &lt;code&gt;[1..]&lt;/code&gt; This will exclude &lt;code&gt;1&lt;/code&gt; index keeping rest same.&lt;br&gt;
Afterward, again splitting this with &lt;code&gt;&amp;amp;&lt;/code&gt; because request might have multiple queries. Then looped &lt;code&gt;query_pairs&lt;/code&gt; splitting with &lt;code&gt;=&lt;/code&gt; once and inserting the values in the &lt;code&gt;HashMap&lt;/code&gt; we created &lt;code&gt;query_params&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Every time I write code like this, a framework developer somewhere sheds a single tear. We're essentially manually parsing query parameters like it's 1999. Next, I'll be setting up my Geocities page and adding a visitor counter.&lt;/p&gt;

&lt;p&gt;Fun fact till now we just manipulated only first line of the protocol. So, let just remove that first line from the &lt;code&gt;request_lines&lt;/code&gt; so, it will no conflict with upcoming stuff.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Remove the request line (already processed)&lt;/span&gt;
&lt;span class="n"&gt;request_lines&lt;/span&gt;&lt;span class="nf"&gt;.remove&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, &lt;strong&gt;third step&lt;/strong&gt; is to extract body and header so to do that we need to separate them by &lt;code&gt;\r\n&lt;/code&gt; in to pieces first will be the headers part and rest is body. Let's get the index of this blank line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;blank_line_index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request_lines&lt;/span&gt;&lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.position&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;line&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After getting the index just spilt off body out&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;body_lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;request_lines&lt;/span&gt;&lt;span class="nf"&gt;.split_off&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blank_line_index&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;body_lines&lt;/span&gt;&lt;span class="nf"&gt;.remove&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="c1"&gt;// Remove the blank line itself&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;body_content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;body_lines&lt;/span&gt;&lt;span class="nf"&gt;.join&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="c1"&gt;// Reconstruct body as a single string&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;.split_off()&lt;/code&gt; will give the part including the index provided so, removed that in the second line with &lt;code&gt;.remove()&lt;/code&gt;. You can observe that I have specified &lt;code&gt;&amp;amp;mut&lt;/code&gt; in variable &lt;code&gt;body_lines&lt;/code&gt; this will give a mutable reference of the &lt;code&gt;body_lines&lt;/code&gt; that is why we are able to remove first line. While implementing I realized for the second time — Rust is not for noobs.&lt;/p&gt;

&lt;p&gt;"Rust is not for noobs" should be their official slogan. The Rust compiler is like that strict teacher who makes you show all your work and won't let you get away with anything. "You're using a mutable reference here, but did you declare ownership rights? I THINK NOT."&lt;/p&gt;

&lt;p&gt;Again stitching body content in a string that can be parsed by &lt;code&gt;serde&lt;/code&gt; or custom parser. I am not going that deep for now. If you have a hobby to waste time reading these types of devs log than you can try yourself to build one parser or pin me to do. (sarcasm)&lt;/p&gt;

&lt;p&gt;Let's be real: if you're still reading this, you either have an unhealthy fascination with HTTP parsing or you're my mom (hi mom!). Either way, I'm concerned about your hobbies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Last step&lt;/strong&gt;, the headers! Well it is similar to query params with for loop, if you are following along then you can, you do this by your own buddy. Come-on, remember what you read in starting.&lt;/p&gt;

&lt;p&gt;Oh, you actually want me to explain the headers parsing too? Fine, here's roughly what it would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;header_line&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;request_lines&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;header_line&lt;/span&gt;&lt;span class="nf"&gt;.trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.is_empty&lt;/span&gt;&lt;span class="p"&gt;()&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="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Some&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="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;header_line&lt;/span&gt;&lt;span class="nf"&gt;.split_once&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="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;header_map&lt;/span&gt;&lt;span class="nf"&gt;.insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="nf"&gt;.trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.to_string&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;It's basically the same idea as parsing query parameters, except with a different delimiter. If you're having trouble with this, maybe programming isn't for you. (I'm kidding, it took me three tries to get this right.)&lt;/p&gt;

&lt;p&gt;And… that's it! That's Day 2.&lt;/p&gt;

&lt;p&gt;You can now instantiate a &lt;code&gt;Request&lt;/code&gt; from a raw TCP stream and access &lt;code&gt;method&lt;/code&gt;, &lt;code&gt;path&lt;/code&gt;, &lt;code&gt;query&lt;/code&gt;, &lt;code&gt;headers&lt;/code&gt;, and &lt;code&gt;body&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you read all this and are still here, maybe you have a strange hobby of reading dev logs like these. Either way, thanks for coming along the ride. 🤝&lt;/p&gt;

&lt;p&gt;Day 2 complete, and all we've done is parse HTTP requests manually, something that libraries have been doing reliably for decades. But hey, we've learned how HTTP works at a fundamental level, which is... useful knowledge to have, I guess? Let's pretend this wasn't a gigantic detour into "things you'll never need to implement yourself" territory.&lt;/p&gt;




&lt;h2&gt;
  
  
  DAY 3: Responding With Style (Or At Least Valid HTTP)
&lt;/h2&gt;

&lt;p&gt;So far we have a rust server where we can handle the request like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;handle_connection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TcpStream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&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;stream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"REQUEST METHOD: {:?}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="py"&gt;.method&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, we need a way to send response in a good manner currently we are doing it manually, and it is boring too.&lt;br&gt;
So, similar to &lt;code&gt;Request&lt;/code&gt; we will create a new struct for &lt;code&gt;Response&lt;/code&gt; than will create some functions to send the response back.&lt;/p&gt;

&lt;p&gt;Boring is programmer-speak for "I've typed this same boilerplate 17 times and I'm starting to wonder if computers were a mistake."&lt;/p&gt;

&lt;p&gt;This is the manual code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;status_line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"HTTP/1.1 200 OK"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;contents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"{'hello': 'World'}"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;contents&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"{status_line}&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;Content-Length: {length}&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;Content-Type: application/json&lt;/span&gt;&lt;span class="se"&gt;\r\n\r\n&lt;/span&gt;&lt;span class="s"&gt;{contents}"&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="nf"&gt;.write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="nf"&gt;.as_bytes&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What we can do is create a function to intake status code, content and optionally headers then return that response. Also, to write this response we can create a function to resolve. In practical let us code to handle some endpoints:&lt;/p&gt;

&lt;p&gt;Look at all those string concatenations and hard-coded header values. This code is begging to be abstracted away. It's like watching someone solve a Rubik's cube by peeling off the stickers — it works, but it hurts my soul.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;handle_connection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TcpStream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&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;stream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="py"&gt;.path&lt;/span&gt;&lt;span class="nf"&gt;.as_str&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="s"&gt;"/hello"&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;default_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"World"&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="py"&gt;.query&lt;/span&gt;&lt;span class="nf"&gt;.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap_or_else&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;default_name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;Hello, {}!&lt;/span&gt;&lt;span class="se"&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;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="nn"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"{{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;Invalid Path&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                    &lt;span class="nn"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&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;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;None&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="nn"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;resolve&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;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;{}&lt;/span&gt;&lt;span class="se"&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;s&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&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;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;None&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nn"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;resolve&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;res&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;match&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="nf"&gt;.write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="nf"&gt;.as_bytes&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&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="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
        &lt;span class="nf"&gt;Err&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="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"FAILED DISPATCHED RESPONSE"&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 this code snippet, we are matching the request path and conditionally executing required code. Here &lt;code&gt;Response::json()&lt;/code&gt; and &lt;code&gt;Response::resolve()&lt;/code&gt; function today, we will implement these are helping us in sending a clear formatted response. &lt;/p&gt;

&lt;p&gt;This is what I call "nested match statement hell." It's like Russian nesting dolls, except each doll contains a slightly different way of saying "something went wrong."&lt;/p&gt;

&lt;p&gt;Let's start by creating a new file &lt;code&gt;response/mod.rs&lt;/code&gt; and add this in &lt;code&gt;lib.rs&lt;/code&gt; file like we did for &lt;code&gt;Request&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;response/mod.rs&lt;/code&gt; we will create a new struct named &lt;code&gt;Response&lt;/code&gt; containing status code, body and headers. Then will implement two functions we decided &lt;code&gt;::json&lt;/code&gt; and &lt;code&gt;::resolve&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;status_text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;String&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="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&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;impl&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u16&lt;/span&gt;&lt;span class="p"&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;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="c1"&gt;// conversion to response code&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&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;Response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// response to string code&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;You know you're writing Rust when half your code is just setting up structures to make the other half cleaner. It's like spending 3 hours organizing your desk before starting a 10-minute task. But hey, that's why we love it!&lt;/p&gt;

&lt;p&gt;These functions are going to be very simple firstly &lt;code&gt;::json()&lt;/code&gt; will calculate the body length and initialize some predefined headers&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;content_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;pre_dermined_headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Content-Length"&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;content_length&lt;/span&gt;&lt;span class="nf"&gt;.to_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;let&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="nf"&gt;.unwrap_or_else&lt;/span&gt;&lt;span class="p"&gt;(||&lt;/span&gt; &lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are using content type to be &lt;code&gt;json&lt;/code&gt; as this function is only for &lt;code&gt;json&lt;/code&gt; if you want you a creation for HTML you can do similarly.&lt;br&gt;
Now, will creating a variable for status text which is a string like for 200 &lt;code&gt;200 OK&lt;/code&gt;, 201 &lt;code&gt;201 Created&lt;/code&gt;, and so on.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;status_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"200 OK"&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="mi"&gt;400&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"400 Bad Request"&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="mi"&gt;500&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"500 Internal Server Error"&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{} Unknown"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&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;I love how we're handling only three HTTP status codes here. It's like opening a restaurant that only serves breakfast, lunch, and dinner, but nothing in between. Want a mid-afternoon snack? Sorry, "418 I'm a teapot" is not on the menu.&lt;/p&gt;

&lt;p&gt;To keep it very simple I've added only three codes, you can extend it if you want.&lt;br&gt;
Lastly, return this response struct and our &lt;code&gt;::json()&lt;/code&gt; function is done.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;Self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;status_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pre_dermined_headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="nf"&gt;.concat&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="nf"&gt;.to_string&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, only &lt;code&gt;::resolve()&lt;/code&gt; function is remaining which is a simple logic to stitch all these stuff together and create a string to send&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;response_str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"HTTP/1.1 {}&lt;/span&gt;&lt;span class="se"&gt;\r\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;response&lt;/span&gt;&lt;span class="py"&gt;.status_text&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="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="py"&gt;.headers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;response_str&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{}: {}&lt;/span&gt;&lt;span class="se"&gt;\r\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;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;response_str&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\r\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;response_str&lt;/span&gt;&lt;span class="nf"&gt;.push_str&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;response&lt;/span&gt;&lt;span class="py"&gt;.body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;response_str&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This &lt;code&gt;resolve&lt;/code&gt; function is basically doing the same string concatenation we were trying to avoid, but now it's encapsulated so we can pretend we don't see it. This is what we call "abstraction" in the industry — putting ugly code in a box and giving it a nice name.&lt;/p&gt;

&lt;p&gt;So far, now we have somewhat usable rust server that intake request and throw response in little good manner.&lt;/p&gt;

&lt;p&gt;It was day 3 of mine, And I think we can create simple to-do API with this. The only remaining is to add multi-threading that is the last chapter.&lt;/p&gt;

&lt;p&gt;"Somewhat usable" is developer-speak for "it works on my machine under perfect conditions, but I wouldn't trust it with actual users." But we're making progress! We've graduated from "completely unusable" to "somewhat usable" in just three days.&lt;/p&gt;




&lt;h2&gt;
  
  
  DAY 4: Multithreading Madness, or "How I Learned to Stop Worrying and Love the Thread Pool"
&lt;/h2&gt;

&lt;p&gt;Today marks the final day of this dev log. It's been an exciting, fulfilling journey — a low-level, hands-on exploration of building an HTTP server in Rust using nothing but the standard library. From parsing raw TCP streams to crafting custom &lt;code&gt;Request&lt;/code&gt; and &lt;code&gt;Response&lt;/code&gt; types, and now finally implementing a thread pool — this was more than a weekend project. It was a masterclass in systems programming, Rust safety, and architectural thinking.&lt;/p&gt;

&lt;p&gt;"Exciting" and "fulfilling" are the words I use in public. In private, it was more like "frustrating" and "why did I choose this again?" But now that it's over, I can pretend it was a smooth, enjoyable experience. That's how memory works!&lt;/p&gt;

&lt;p&gt;Let's dive into Day 4, which was all about making our server concurrent and robust. But as with all systems work, the deeper story isn't just &lt;em&gt;what&lt;/em&gt; I built — it's &lt;em&gt;why&lt;/em&gt; I built it that way.&lt;/p&gt;

&lt;p&gt;Or more accurately, &lt;em&gt;why&lt;/em&gt; I thought reinventing thread pooling was a good use of my time when perfectly good libraries exist. But here we are.&lt;/p&gt;

&lt;h2&gt;
  
  
  Motivation: From Sequential to Concurrent
&lt;/h2&gt;

&lt;p&gt;Initially, our server could handle one request at a time. If a user hit &lt;code&gt;/hello&lt;/code&gt;, and inside that handler we added something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;time&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_secs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The whole server would freeze for 5 seconds. No other request could get through. That's obviously not how real-world web servers behave — not even the simplest ones.&lt;/p&gt;

&lt;p&gt;It's like having only one cashier at a grocery store who also has to bag your items, fetch missing products, and check inventory. You'd have a line out the door faster than you can say "unexpected item in bagging area."&lt;/p&gt;

&lt;p&gt;The natural next step: let's add multithreading.&lt;/p&gt;

&lt;p&gt;I began with a naive approach, just like any curious Rustacean learning the ropes would.&lt;/p&gt;

&lt;h2&gt;
  
  
  First Stop: Spawning a New Thread per Request
&lt;/h2&gt;

&lt;p&gt;Here's the naive, simple version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="nf"&gt;.incoming&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(||&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;handle_connection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&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 actually works well for testing — the server no longer blocks on a single request. We can add delay inside the handler, and other clients won't wait.&lt;/p&gt;

&lt;p&gt;But here's the caveat: we're spawning a new thread for every single connection.&lt;/p&gt;

&lt;p&gt;What happens if someone sends us 1,000 requests per second? We spawn 1,000 threads per second. The system dies fast. This is a textbook Denial of Service vector.&lt;/p&gt;

&lt;p&gt;It's like hiring a new employee for each customer that walks into your store. By the end of the day, you'd have 500 employees standing around, payroll would be impossible, and your store would be too crowded for any actual customers.&lt;/p&gt;

&lt;p&gt;So I pivoted to a better design.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Thread Pool Model
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;Thread Pool&lt;/strong&gt; is like a team of waiters at a restaurant. You don't hire a new waiter for every customer. You just hand tasks to whoever's available.&lt;/p&gt;

&lt;p&gt;Or think of it as a group of interns eagerly waiting to do your grunt work. "You there, handle this HTTP request! You, parse this JSON! The rest of you, stand by for more tedious tasks!"&lt;/p&gt;

&lt;p&gt;Technically, a thread pool keeps a fixed number of threads alive. Each thread waits for a job. When a job (like an incoming HTTP request) arrives, it's pushed into a shared queue. The next available thread grabs it and handles it.&lt;/p&gt;

&lt;p&gt;This avoids overloading the OS scheduler with thousands of threads while still enabling concurrency.&lt;/p&gt;

&lt;p&gt;In Rust, building a thread pool from scratch meant juggling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Threads&lt;/strong&gt; (from the standard library),&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Channels&lt;/strong&gt; (&lt;code&gt;std::sync::mpsc&lt;/code&gt;) for sending jobs,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Mutexes&lt;/strong&gt; and &lt;strong&gt;Arcs&lt;/strong&gt; for safe, shared ownership of the job receiver.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's walk through the code.&lt;/p&gt;

&lt;p&gt;By "let's walk through the code," I mean "brace yourself for a cavalcade of Rust's most intimidating concurrency primitives." If you've never seen an &lt;code&gt;Arc&amp;lt;Mutex&amp;lt;mpsc::Receiver&amp;lt;Box&amp;lt;dyn FnOnce() + Send + 'static&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/code&gt; before, well... you're about to.&lt;/p&gt;

&lt;h2&gt;
  
  
  📦 The ThreadPool Code: Building a Worker Army
&lt;/h2&gt;

&lt;p&gt;We created a new module: &lt;code&gt;lib.rs&lt;/code&gt; (or &lt;code&gt;thread_pool.rs&lt;/code&gt; if separated), which defines &lt;code&gt;ThreadPool&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;ThreadPool&lt;/code&gt; Struct
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;ThreadPool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;workers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Worker&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nn"&gt;mpsc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Sender&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Job&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;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;It holds:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;workers&lt;/code&gt;: a vector of threads.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;sender&lt;/code&gt;: a channel to send jobs into the queue.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We define &lt;code&gt;Job&lt;/code&gt; like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Job&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="nf"&gt;FnOnce&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;Send&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="k"&gt;'static&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A job is just a closure you can run once. It must be thread-safe (&lt;code&gt;Send&lt;/code&gt;) and have a static lifetime (since threads can outlive their scopes).&lt;/p&gt;

&lt;p&gt;Look at that type alias. If you can read that and immediately understand what it means, congratulations! You've achieved Rust enlightenment. For the rest of us mortals, it's a boxed closure that can be sent between threads and lives for the entire program.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the Pool
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ThreadPool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;assert!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;mpsc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;receiver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Arc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Mutex&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;workers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Vec&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;with_capacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&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;id&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&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;workers&lt;/span&gt;&lt;span class="nf"&gt;.push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;Arc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;clone&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;receiver&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;ThreadPool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;workers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sender&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;ul&gt;
&lt;li&gt;&lt;p&gt;We create a sender/receiver channel pair.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The receiver is wrapped in &lt;code&gt;Arc&amp;lt;Mutex&amp;lt;&amp;gt;&amp;gt;&lt;/code&gt;, so it can be safely shared between threads.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Each worker is spawned with a cloned handle to the shared receiver.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That &lt;code&gt;Arc&amp;lt;Mutex&amp;lt;&amp;gt;&amp;gt;&lt;/code&gt; wrapper is the Rust equivalent of putting something in a special box with a lock on it, then making photocopies of the box. Everyone gets their own copy of the box, but there's still only one thing inside, and only one person can unlock it at a time.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Worker: Thread That Never Sleeps
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Worker&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nn"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;JoinHandle&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;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;Each worker has an ID and a thread handle. Inside &lt;code&gt;Worker::new&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Arc&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Mutex&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nn"&gt;mpsc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Receiver&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Job&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Worker&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;thread&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;move&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="k"&gt;loop&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="nf"&gt;.lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.recv&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;job&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Execute the closure!&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nf"&gt;Err&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="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Worker {id} disconnected; shutting down."&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="p"&gt;});&lt;/span&gt;

    &lt;span class="n"&gt;Worker&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;thread&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;Each thread loops forever, waiting for a job via the channel. If it gets one, it runs it. If the channel closes, it breaks the loop and shuts down.&lt;/p&gt;

&lt;p&gt;You know what this reminds me of? Those poor souls at the fast-food drive-thru window, eternally waiting for the next customer to pull up, ready to take their order until the restaurant closes (the channel shuts down). Except in our case, the orders are HTTP requests, and the food is... JSON responses? This metaphor might be breaking down.&lt;/p&gt;

&lt;h3&gt;
  
  
  Submitting Work
&lt;/h3&gt;

&lt;p&gt;Back in &lt;code&gt;main.rs&lt;/code&gt;, we replace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nf"&gt;handle_connection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;ThreadPool&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&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;stream&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="nf"&gt;.incoming&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="nf"&gt;.execute&lt;/span&gt;&lt;span class="p"&gt;(||&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;handle_connection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&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;And define &lt;code&gt;execute&lt;/code&gt; as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;where&lt;/span&gt;
    &lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;FnOnce&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;Send&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="k"&gt;'static&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.sender&lt;/span&gt;&lt;span class="nf"&gt;.as_ref&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&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="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&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 sends the job to the shared channel, where a worker picks it up.&lt;/p&gt;

&lt;p&gt;Notice how we're using generic function parameters, type bounds, and lifetime specifications just to... send a function to another thread. Rust makes simple things complex so that complex things can be simple. It's like doing extensive paperwork to get a library card, but once you have it, you can borrow any book without further hassle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cleaning Up: Implementing Drop for ThreadPool
&lt;/h2&gt;

&lt;p&gt;When our server exits, we don't want zombie threads. So we implement &lt;code&gt;Drop&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="nb"&gt;Drop&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;ThreadPool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;drop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;drop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.sender&lt;/span&gt;&lt;span class="nf"&gt;.take&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// Closes the sending side of the channel&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;worker&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.workers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Shutting down worker {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="py"&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="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="py"&gt;.thread&lt;/span&gt;&lt;span class="nf"&gt;.take&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="nf"&gt;.join&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&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 cleanly shuts down each worker.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Drop&lt;/code&gt; trait is Rust's version of a cleanup crew. It's like telling your party guests "Please take your belongings with you when you leave" instead of finding random shoes and jackets in your house weeks later. Memory management is just good manners.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧱 The Final Structure of the Server
&lt;/h2&gt;

&lt;p&gt;By the end of Day 4, here's what the server looks like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Request&lt;/code&gt;: Parses method, path, headers, query params, body from raw bytes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Response&lt;/code&gt;: Provides &lt;code&gt;Response::json&lt;/code&gt; and &lt;code&gt;Response::resolve&lt;/code&gt; to build HTTP responses.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;ThreadPool&lt;/code&gt;: Handles incoming connections in parallel.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;handle_connection&lt;/code&gt;: Contains the actual routing and logic for endpoints like &lt;code&gt;/hello&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you step back and look at it, we've essentially recreated tiny, limited versions of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;hyper&lt;/code&gt; (HTTP parsing)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;serde_json&lt;/code&gt; (JSON handling, though barely)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tokio&lt;/code&gt; or &lt;code&gt;rayon&lt;/code&gt; (concurrency)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All to... parse an HTTP request and return "Hello, World!" I'm not sure whether to feel proud or deeply question my life choices.&lt;/p&gt;

&lt;h2&gt;
  
  
  🎉 Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Five days ago, I started with nothing but an idea: can I build a fully working HTTP server using just the Rust standard library?&lt;/p&gt;

&lt;p&gt;Five days ago, I also had friends, social interactions, and a healthy relationship with sunlight. I've since traded these for the satisfaction of parsing HTTP headers manually.&lt;/p&gt;

&lt;p&gt;Here's what I ended up with:&lt;/p&gt;

&lt;p&gt;✅ Parsed raw TCP streams into &lt;code&gt;Request&lt;/code&gt; structs&lt;br&gt;&lt;br&gt;
✅ Built a structured &lt;code&gt;Response&lt;/code&gt; system with content-type headers&lt;br&gt;&lt;br&gt;
✅ Implemented conditional routing (&lt;code&gt;/hello&lt;/code&gt;) with query param parsing&lt;br&gt;&lt;br&gt;
✅ Added a concurrent thread pool to handle multiple connections&lt;br&gt;&lt;br&gt;
✅ Cleaned up threads gracefully using the &lt;code&gt;Drop&lt;/code&gt; trait&lt;br&gt;&lt;br&gt;
✅ Never used a single external crate&lt;br&gt;&lt;br&gt;
✅ Questioned my sanity approximately 17 times&lt;/p&gt;

&lt;p&gt;It wasn't just about learning how to write TCP servers. It was about understanding the internals that most high-level frameworks abstract away.&lt;/p&gt;

&lt;p&gt;It's like learning how a car engine works instead of just driving the car. Will this knowledge help me get to the grocery store faster? Absolutely not. But will it make me feel superior when talking to people who just drive their cars without knowing what a carburetor is? You bet.&lt;/p&gt;

&lt;p&gt;This server is far from production-ready, but it's clear, readable, and educational. You can easily extend it with features like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;POST&lt;/code&gt; form data body parsing&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;File upload/download&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Static file serving&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Logging middleware&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;TLS support (with crates like &lt;code&gt;native-tls&lt;/code&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Async I/O using &lt;code&gt;tokio&lt;/code&gt; (if leaving stdlib constraint)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A will to live (this one might be harder to implement)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But for now, I'm happy.&lt;/p&gt;

&lt;p&gt;This journey reminded me that &lt;em&gt;you don't always need more abstractions&lt;/em&gt;. Sometimes, starting from scratch helps you understand what abstractions are truly worth.&lt;/p&gt;

&lt;p&gt;It also reminded me that there's a reason why web frameworks exist, and why nobody in their right mind parses HTTP manually in production. But hey, learning is fun, right?&lt;/p&gt;

&lt;p&gt;Thank you, Rust, for making low-level work feel safe and expressive.&lt;/p&gt;

&lt;p&gt;And thank you, dear reader, for sticking with me through this unnecessarily detailed account of my descent into HTTP parsing madness.&lt;/p&gt;




&lt;p&gt;🔚 &lt;strong&gt;End of Dev Log&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;💡 If you read this and decide to build your own server from scratch — do it. You'll never look at &lt;code&gt;actix-web&lt;/code&gt; or &lt;code&gt;warp&lt;/code&gt; the same way again. You'll look at them with tears of gratitude in your eyes, whispering "thank you for existing" as you add them to your dependencies.&lt;/p&gt;

&lt;p&gt;🛠️ Signing off — see you in the next low-level adventure! (Which, if I'm smart, will involve a lot more use of established libraries and a lot less reinventing of wheels.)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/priyanshu-verma-pz/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/PriyanshuPz/rust-server" rel="noopener noreferrer"&gt;Project GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>programming</category>
      <category>scratch</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How to Find Build-Worthy Ideas</title>
      <dc:creator>Priyanshu Verma</dc:creator>
      <pubDate>Fri, 18 Apr 2025 08:22:29 +0000</pubDate>
      <link>https://dev.to/priyanshuverma/how-to-find-build-worthy-ideas-19o3</link>
      <guid>https://dev.to/priyanshuverma/how-to-find-build-worthy-ideas-19o3</guid>
      <description>&lt;p&gt;&lt;em&gt;Hi again&lt;/em&gt; 👋&lt;br&gt;&lt;br&gt;
This blog is a part of the &lt;strong&gt;&lt;a href="https://dev.to/priyanshuverma/intro-build-what-you-imagine-4mml"&gt;Intro – Build What You Imagine&lt;/a&gt;&lt;/strong&gt; Series. Feel free to check out other parts and learn along the way.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 Problem: Finding Project Ideas Isn’t Hard
&lt;/h2&gt;

&lt;p&gt;Finding project ideas isn’t as difficult as most people think. You're surrounded by problems every day—from the moment you wake up to when you go to bed.&lt;/p&gt;

&lt;p&gt;Let me give you a few personal examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;I want a product that shows &lt;strong&gt;all my notifications in one place&lt;/strong&gt; when I wake up.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A plugin that can &lt;strong&gt;auto-generate a to-do list&lt;/strong&gt; and show &lt;strong&gt;yesterday’s journal in Obsidian&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An app where I can save my thoughts, and then ask AI to &lt;strong&gt;summarize how my day was&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A &lt;strong&gt;simple util app&lt;/strong&gt; to use my phone as a &lt;strong&gt;PC mic&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are tiny daily pain points. Some already have solutions, but they’re either filled with ads, not customizable, or need me to share personal data—which I’m not comfortable with. If the tool were &lt;strong&gt;open-source&lt;/strong&gt; or &lt;strong&gt;self-hostable&lt;/strong&gt;, I’d try it. But in many cases, they simply don’t exist.&lt;/p&gt;

&lt;p&gt;So, what’s the alternative?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Build these apps yourself.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Yes, seriously. Just like I noticed these small gaps, you have them too. You’ve probably caught yourself thinking, &lt;em&gt;“This app should really have this one extra feature…”&lt;/em&gt;&lt;br&gt;&lt;br&gt;
And then maybe you thought: &lt;em&gt;“I can build this.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That’s the moment you grab onto. These small ideas may not make you money, but they &lt;strong&gt;teach you a lot&lt;/strong&gt;, &lt;strong&gt;sharpen your skills&lt;/strong&gt;, and if you solve your own problem well—you now have something to show off with pride.&lt;/p&gt;




&lt;h2&gt;
  
  
  💸 I Have an Idea. Can I Make Money From It?
&lt;/h2&gt;

&lt;p&gt;Great! You’ve found an idea you’re excited to build. But now you’re wondering—&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Can I earn money from it?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The short answer?&lt;br&gt;&lt;br&gt;
You can. But don’t think about money &lt;strong&gt;right now&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If your first goal is &lt;strong&gt;money&lt;/strong&gt;, your focus shifts away from building.&lt;br&gt;&lt;br&gt;
If you chase money first, you’ll likely get &lt;strong&gt;neither skills nor money&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s be clear—&lt;strong&gt;building projects is an art&lt;/strong&gt;, not just business.&lt;/p&gt;

&lt;p&gt;I’m not saying you shouldn’t aim to monetize. But before that, build the &lt;strong&gt;skills&lt;/strong&gt;. If you can solve a couple of personal problems and you’re happy using your own product, then it’s ready for the world.&lt;/p&gt;

&lt;p&gt;Share it online. Launch it on &lt;strong&gt;Product Hunt&lt;/strong&gt; or LinkedIn.&lt;br&gt;&lt;br&gt;
You’ll always find people who share the same problem—and if they love it, you’ll &lt;strong&gt;naturally find a way to monetize&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  👨‍💻 Do You &lt;em&gt;Really&lt;/em&gt; Want to Be a Developer?
&lt;/h2&gt;

&lt;p&gt;If you’re a beginner, especially someone who picked computer science &lt;strong&gt;just for the money&lt;/strong&gt;—there’s a hard truth:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You’ll likely struggle if you're not motivated by curiosity.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;CS and development require patience, persistence, and a desire to create.&lt;br&gt;&lt;br&gt;
If your initial goal is only income, you’ll burn out fast.&lt;/p&gt;

&lt;p&gt;So, what should you do?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Build for fun.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Build to learn.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Make anything:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Websites&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Mobile apps&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CLI tools&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Games&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Math animations&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;3D models&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A unified chat app that runs in your terminal and on your phone&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Your own cloud console&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🌌 &lt;strong&gt;The sky is the limit.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Ideas are &lt;strong&gt;everywhere&lt;/strong&gt;—most people just ignore them. Builders don’t.&lt;/p&gt;

&lt;p&gt;The key is to &lt;strong&gt;start building and keep building&lt;/strong&gt;. If you document your journey online, you’ll open doors: internships, jobs, freelance gigs, and more.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Build for skill first.&lt;br&gt;&lt;br&gt;
Money is a byproduct.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  ✍️ What’s Next?
&lt;/h2&gt;

&lt;p&gt;By now, you’ve probably got a few ideas floating in your head. Here’s what to do next:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Write your ideas down.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Yes, physically—pen and paper. Don’t use AI yet.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Define the problem&lt;/strong&gt; each idea solves.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Resist jumping to AI&lt;/strong&gt; to ask how to build it. Why?&lt;br&gt;&lt;br&gt;
Because AI can overwhelm you and show you someone else’s way of doing it.&lt;br&gt;&lt;br&gt;
Your idea is &lt;strong&gt;unique&lt;/strong&gt;. You’re solving a &lt;strong&gt;personal&lt;/strong&gt; problem.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Avoid instant setups or templates&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
You’ll end up copy-pasting without understanding the core.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Keep it simple.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Don’t overengineer. Solve just &lt;strong&gt;2 small problems&lt;/strong&gt;. Keep the scope tight and clear.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Later in this series, I’ll show you &lt;strong&gt;how to use AI&lt;/strong&gt; productively during the build phase. But not now. First, learn to think, break down problems, and structure your ideas yourself.&lt;/p&gt;




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

&lt;p&gt;The goal of this post was to help you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Find build-worthy ideas&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Get excited about building&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Let go of the money-first mindset (for now)&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Building something just for yourself, even if no one else uses it, is worth it.&lt;br&gt;&lt;br&gt;
You learn. You grow. You create.&lt;/p&gt;

&lt;p&gt;We’ll get into &lt;strong&gt;execution and building&lt;/strong&gt; in future posts.&lt;br&gt;&lt;br&gt;
For now, grab a notebook, look around you, and &lt;strong&gt;start writing your ideas&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That’s it for today.&lt;/p&gt;

&lt;p&gt;Thanks for reading.&lt;br&gt;&lt;br&gt;
— &lt;em&gt;Priyanshu Verma&lt;/em&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>productivity</category>
      <category>career</category>
      <category>learning</category>
    </item>
  </channel>
</rss>
