An HTTP Server From Scratch
intermediate20 min readLesson 117 of 143
Node's http module in 15 lines, the request/response lifecycle, and what a framework does for you.
You've called APIs for months. Now build the receiving end โ with zero frameworks, so you know what they actually do.
The minimal server
import http from "node:http";
const server = http.createServer((req, res) => {
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify({ ok: true }));
});
server.listen(3000, () => console.log("on :3000"));
createServer registers a callback that runs for every request. The two arguments are everything:
- req (IncomingMessage):
req.method("GET", "POST"...),req.url(path + query),req.headers, and the body as a stream (POST bodies arrive in chunks โ you assemble them). - res (ServerResponse):
res.writeHead(status, headers),res.end(body). Forgetres.endand the client hangs forever.
Reading a request body
let body = "";
req.on("data", (chunk) => {
body += chunk;
});
req.on("end", () => {
const data = JSON.parse(body); // wrap in try/catch: bad JSON is user input
res.end(JSON.stringify({ got: data }));
});
This is the stream dance every framework hides behind req.json().
Status codes that mean something
- 200 OK โ success with body ยท 201 Created โ after a successful POST that made something (set
Locationheader to the new resource) - 400 Bad Request โ the client sent garbage (validation failure)
- 401 Unauthorized โ who are you? ยท 403 Forbidden โ I know you; no.
- 404 Not Found ยท 409 Conflict (duplicate email) ยท 500 โ our fault, log it
Correct codes are part of your API's contract. A 404 for "validation failed" makes clients build error handling on lies.
What frameworks buy you
Routing by pattern (app.get("/users/:id")), body parsing, middleware chaining, error normalization. Express/Fastify are conveniences over this callback โ knowing the callback means you can debug through any framework.