Before the framework
Frameworks feel like magic until you've done it yourself once. Parse the URL, choose a route by method and path, read a JSON body from the request stream — then Express will make perfect sense.
URL, method and body
import http from "node:http";
const dishes = [{ id: 1, name: "Momo", price: 180 }];
async function readJson(req) {
let raw = "";
for await (const chunk of req) raw += chunk;
return raw ? JSON.parse(raw) : {};
}
function send(res, status, data) {
res.writeHead(status, { "Content-Type": "application/json" });
res.end(JSON.stringify(data));
}
http
.createServer(async (req, res) => {
const url = new URL(req.url, "http://localhost");
if (req.method === "GET" && url.pathname === "/dishes") {
const max = Number(url.searchParams.get("max") ?? Infinity);
return send(res, 200, dishes.filter((d) => d.price <= max));
}
if (req.method === "POST" && url.pathname === "/dishes") {
const body = await readJson(req);
const dish = { id: dishes.length + 1, name: body.name, price: body.price };
dishes.push(dish);
return send(res, 201, dish);
}
send(res, 404, { error: "Not found" });
})
.listen(3000);
const created = await fetch("http://localhost:3000/dishes", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: "Thukpa", price: 220 }),
});
console.log(created.status, await created.json());
console.log(await (await fetch("http://localhost:3000/dishes?max=200")).json());- This works, but grows messy fast: every route is an if-statement, path parameters need regexes, errors need handling everywhere.
- That's exactly what Express (next lesson) cleans up.