<?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>Forem: pradeep kumar</title>
    <description>The latest articles on Forem by pradeep kumar (@exvillager).</description>
    <link>https://forem.com/exvillager</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%2F2613606%2Fbc2fb5c7-f853-46fe-bfaf-e4310cb65527.jpg</url>
      <title>Forem: pradeep kumar</title>
      <link>https://forem.com/exvillager</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/exvillager"/>
    <language>en</language>
    <item>
      <title>How I Built My Own Web Framework in Bun</title>
      <dc:creator>pradeep kumar</dc:creator>
      <pubDate>Tue, 03 Mar 2026 17:36:19 +0000</pubDate>
      <link>https://forem.com/exvillager/how-i-made-my-own-backend-web-framework-like-expresshono-from-scratch-in-bun--3e81</link>
      <guid>https://forem.com/exvillager/how-i-made-my-own-backend-web-framework-like-expresshono-from-scratch-in-bun--3e81</guid>
      <description>&lt;p&gt;So, it was around June or July 2024, and I was making the same boring API in Express. I was wondering how the fu*k these things even work under the hood. So I thought, why not create my own small library like Express to understand the ‘under the hood’?&lt;/p&gt;

&lt;p&gt;So I started building my own library, diesel.js. First, I just added simple methods like .get, .post, etc. But there was a problem. The user gives a path and a handler like this: app.get("/user", userHandler). I had to store these somewhere in my library class so when the client makes an API request to the server, I can route the client request to the correct API handler. For that, I used a simple object {} and stored handlers like this: diesel.routes[method+path] = Handler.&lt;/p&gt;

&lt;p&gt;For handling the actual request, I made a handler function where I had to parse the incoming request URL (like &lt;a href="http://localhost:3000/user" rel="noopener noreferrer"&gt;http://localhost:3000/user&lt;/a&gt; to /user). then I had to match this path to my route to find the correct handler, like &lt;code&gt;const matchedHandler = diesel.routes[req.method+path]&lt;/code&gt;. then, after I get the matching handler, I call the handler with Bun.js’s default incomingRequest object.&lt;/p&gt;

&lt;p&gt;After building the first version, I was able to understand how Express &amp;amp; Fastify works under the hood. But my curiosity didn’t stop here.&lt;/p&gt;

&lt;p&gt;My framework had many missing features that needed to get implemented, like middleware support and advanced path route matching like how express or fastify does.&lt;/p&gt;

&lt;p&gt;So I started to add middleware support first.&lt;/p&gt;

&lt;p&gt;But, but, but what is a &lt;code&gt;middleware&lt;/code&gt; anyway? Middleware is just a function which gets invoked before the main handler.&lt;/p&gt;

&lt;p&gt;and there are mainly two kinds of middlewares , one is global and second one is route specific.&lt;/p&gt;

&lt;p&gt;But what is global middleware? Well, global middleware is just a list of middlewares which needs to get invoked first even if the route specific handler matches or not. It’s meant to run anyway.&lt;/p&gt;

&lt;p&gt;And route specific middleware means it should only be invoked when the request comes to a specific route, like &lt;code&gt;app.useMiddleware("/user", function(){console.log("i'm a global middleware")})&lt;/code&gt;. &lt;br&gt;
Now this middleware function will only be invoked when the request comes on &lt;code&gt;/user&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For storing global middleware, I used a normal &lt;code&gt;array[]&lt;/code&gt;, and for storing route specific middleware, I used a Map (I could have used a plain object too). Then I updated my handleRequest function to check &lt;code&gt;if diesel.globalMiddleware.length &amp;gt; 0&lt;/code&gt; exists, loop over them, and invoke them. Then to check for route specific middleware, I did &lt;code&gt;const routeMiddleware = diesel.routeMiddleware(path)&lt;/code&gt;, and if the middleware exists, then again loop over them and invoke each one by one. Finally, I was able to add middleware support to my library.&lt;/p&gt;

&lt;p&gt;But the biggest problem still was the routing system. The plain object for storing the user given path was only capable of handling static routes like &lt;code&gt;/user/login&lt;/code&gt;. It can’t do something like dynamic path matching &lt;code&gt;(/user/:id, where :id means this ID can be anything)&lt;/code&gt; or a wildcard route like &lt;code&gt;/assets/*&lt;/code&gt; (where * means that if the incoming request starts with the path &lt;code&gt;/assets&lt;/code&gt;, then ignore the rest). Our plain object was incapable of doing these things. For handling this, I needed a smart router, something like a Trie router which can handle dynamic and wildcard routes.&lt;/p&gt;

&lt;p&gt;Here is the link to the Medium article where i explained: How I built my own Trie based HTTP router.&lt;/p&gt;

&lt;p&gt;And here is the diesel‘s github link : &lt;a href="https://github.com/pradeepbgs/diesel" rel="noopener noreferrer"&gt;https://github.com/pradeepbgs/diesel&lt;/a&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>express</category>
      <category>scratch</category>
      <category>honojs</category>
    </item>
  </channel>
</rss>
