What Is This?
A handcrafted HTTP/1.1 server built without using Node.js's built-in http module. It works directly at the TCP level using the net module, manually implementing all HTTP parsing, routing, middleware, and response formatting. The server ships with a working Todo CRUD API backed by a flat-file database as a demo application.
Zero external dependencies everything is built from first principles.
How It Works
The HTTP Engine
The core server creates a raw TCP server with net.createServer() and exposes an Express-like API — app.route(), app.use(), and app.listen() — all custom-built from scratch.
On each incoming TCP connection, it:
- Splits the raw buffer into headers and body at
\r\n\r\n - Parses the HTTP request line, headers, route params, and query strings
- Runs the middleware chain sequentially with a
next()pattern - Matches a route and calls its handler, or returns a 404
Request Parser
Manually parses raw HTTP text extracting method, path, HTTP version, headers, dynamic route parameters (:id patterns), and query strings. Also handles OPTIONS/CORS preflight requests.
Response Builder
Constructs valid HTTP/1.1 responses from scratch — status line, standard headers (Date, Content-Type, Content-Length, Connection), and body — written to the TCP socket with proper \r\n\r\n separation.
Middleware Layer
Three middlewares implemented:
- Static file server — serves files from a
public/directory with correct MIME types - Body parser — handles
application/jsonandmultipart/form-data(boundary-based MIME splitting implemented manually following RFC 1341) - CORS — sets cross-origin headers and handles preflight
Demo: Todo CRUD API
A fully functional REST API demonstrating all the framework features:
GET /task → Fetch all tasks
POST /task → Create a new task
PUT /task/:id → Update a task by ID
PUT /task/done/:id → Toggle task completion
DELETE /task/:id → Delete a task by ID
POST /file → Upload a file via multipart/form-data
Tasks are persisted as concatenated JSON objects in a flat text file — no database needed.
Key Design Decisions
- No framework, no
httpmodule — the entire HTTP lifecycle is built from first principles using only raw TCP sockets - Express-like middleware chain — middlewares receive
(req, res, next, body)and callnext()to pass control, with aheadersSentguard to prevent double-writes - Dynamic routing — route params like
:idare resolved at request time by comparing path segments against registered route patterns - Manual multipart parsing — boundary-based MIME splitting without any library
- MIME type registry — maps content types to their serialization functions for encoding/decoding
What I Learned
Building an HTTP server from the TCP level up revealed exactly what frameworks like Express abstract away — from raw byte buffer handling and header parsing to the middleware chain pattern and content negotiation. Implementing multipart form data parsing manually gave me a deep appreciation for the HTTP specification and how file uploads actually work at the wire level.