Lesson 2 of 9 · 20m
HTTP Without a Framework
Method, path, headers, status, body — the five things every request is, before Express adds magic.
Every HTTP server on Earth does the same five things: it reads the method and path off the request line, scans the headers, reads the body, and writes back a status and a body. Frameworks wrap that in routing tables and middleware — but peel any of them back and the machinery is identical. Write one by hand once and the magic disappears.
A real server, no framework
import http from "node:http";
const server = http.createServer((req, res) => {
if (req.method === "GET" && req.url === "/health") {
res.writeHead(200, { "content-type": "application/json" });
res.end(JSON.stringify({ ok: true }));
return;
}
res.writeHead(404, { "content-type": "application/json" });
res.end(JSON.stringify({ error: "not found" }));
});
server.listen(3000);That is a complete HTTP server. req.method and req.url are the routing decision. res.writeHead(status, headers) sets the response metadata. res.end(body) sends it. Everything Express, Hono, or Fastify does is sugar on top of this loop.
Reading the body is a stream
let body = "";
for await (const chunk of req) body += chunk;
const data = JSON.parse(body || "{}");Requests are streams — the body arrives in chunks. Frameworks hide this behind req.body or await req.json(), but the stream is what they are consuming.
Try it yourself — the routing decision, live
const req = { method: "GET", url: "/users/42" };
const [route, id] = req.url.split("/").slice(1);
console.log("method:", req.method, "| route:", route, "| param:", id);Why it matters
When your framework's route does something weird, the answer is always in these five fields — method, path, headers, body, status. The framework is a lookup table on top; the protocol is underneath.