From scratch to framework
What you just did vs what a framework does
In the last lesson, we built a working server from scratch. It handled GET, POST, and 404. It read headers, parsed bodies, and returned JSON responses. And it was verbose, repetitive, and painful to maintain. Now let’s look at the same functionality with a framework and see exactly what all that boilerplate was buying us.
Routing
Here is how we routed requests from scratch:
if (req.method === "GET" && url.pathname.startsWith("/books/")) {
const id = url.pathname.split("/")[2];
// ...
} Manual if-else chains. String splitting to extract path parameters. Fragile, easy to get wrong.
Here is the same thing with Hectoday HTTP:
route.get("/books/:id", {
request: { params: z.object({ id: z.string() }) },
resolve: (c) => {
if (!c.input.ok) return Response.json({ error: c.input.issues }, { status: 400 });
const id = c.input.params.id;
// ...
},
}); The framework parses the URL, matches the route pattern, extracts :id from the path, and validates it against the schema. It hands you c.input.params.id as a clean, validated value. No string splitting. No if-else. No manual path matching.
Body parsing and validation
From scratch, you had two separate problems: parsing the body and validating its contents.
// Parsing
let body = "";
for await (const chunk of req) body += chunk;
const data = JSON.parse(body); // Might throw SyntaxError
// Validation
if (!data.title || typeof data.title !== "string") {
res.writeHead(400);
res.end(JSON.stringify({ error: "title is required" }));
return;
} Manual body streaming, manual JSON parsing with a try-catch, manual type checks for every field. Imagine doing this for an object with 10 fields, some optional, some with constraints like “must be between 1 and 5.”
Hectoday HTTP handles both in one step. You define a Zod schema in request, and the framework parses the JSON body and validates it against the schema:
route.post("/books", {
request: { body: z.object({ title: z.string(), genre: z.string() }) },
resolve: (c) => {
if (!c.input.ok) {
return Response.json(
{ error: "Validation failed", details: c.input.issues },
{ status: 400 },
);
}
// c.input.body is typed and validated — { title: string, genre: string }
},
}); When you define a body schema, the framework reads the request body, parses the JSON, and validates it. If validation fails, c.input.ok is false and c.input.issues tells you exactly what was wrong. If it passes, c.input.body gives you the parsed, typed data. No manual JSON.parse, no Content-Type checking, no type assertions.
Error handling
From scratch:
try {
// ... route logic
} catch (err) {
res.writeHead(500);
res.end(JSON.stringify({ error: "Internal error" }));
} You had to wrap every route in a try-catch. Miss one, and an unhandled error crashes the server.
With Hectoday HTTP:
setup({
onError: ({ error, request }) => {
return handleError(error, request);
},
routes: [
/* ... */
],
}); One error handler for all routes. If any route throws an unexpected error, it gets caught here. No try-catch in individual handlers. The Error Handling course builds on this pattern.
Response building
From scratch:
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify(data)); Two lines, every time. Set the headers, serialize the data, send it.
With Hectoday HTTP:
return Response.json(data); // Content-Type, serialization, status 200
return Response.json(data, { status: 201 }); // Custom status One line. Response.json handles the Content-Type header, JSON serialization, and status code.
What this course taught you
The framework handles the mechanics. But you need to understand what those mechanics are. When you see Response.json(data, { status: 201 }), you now know exactly what that does: it creates an HTTP response with status code 201, a Content-Type: application/json header, and a body containing the JSON-serialized data. When you see c.input.params.id, you know that came from parsing the URL path. When you see a 403 error, you know it means “authenticated but not authorized.”
Every subsequent course in this series (Authentication, REST API Design, Error Handling, Caching, and all the rest) builds on the HTTP concepts from this course. The framework is the tool. HTTP is the language. Now you speak the language.
Exercises
Exercise 1: Take the from-scratch server from the previous lesson and rewrite it using Hectoday HTTP. Compare the line count.
Exercise 2: Add Zod validation to both versions. Compare the effort it takes in each.
Exercise 3: Add a global error handler to both versions. Notice how much less code the framework version needs.
What is the most important thing a framework like Hectoday HTTP does for you?