-
Notifications
You must be signed in to change notification settings - Fork 7
Express API and validation
Summary: This page details advanced concepts of Express routing in StartER, including using factories to simplify URL parameter conversion and data validation with Zod.
The backend must ensure that the data received via HTTP requests matches expectations before processing it. To reduce boilerplate code, StartER provides two utilities in src/express/helpers: createParamConverter and createValidator.
"Param converters" transform a URL parameter (like :itemId) into a fully loaded business object (an entity) from the database.
The itemParamConverter.ts file uses the createParamConverter factory:
import { createParamConverter } from "../../helpers/paramConverter";
import itemRepository from "./itemRepository";
export default createParamConverter(itemRepository, "item");This single line of code:
- Declares that we want to convert a parameter using
itemRepository. - Specifies that the found entity will be injected into
req.item. - Automatically handles errors: if the ID does not exist, it returns a
404 Not Found(or204 No Contentfor aDELETErequest).
To make req.item recognized by TypeScript, we extend the Request interface:
declare global {
namespace Express {
interface Request {
item: Item;
}
}
}Before modifying data, StartER uses Zod via the createValidator factory to validate and sanitize req.body.
Example in itemValidator.ts:
import { z } from "zod";
import { createValidator } from "../../helpers/validation";
const itemDTOSchema = z.object({
title: z.string().max(255),
user_id: z.number(),
});
export default createValidator(itemDTOSchema, (req) => ({
...req.body,
// Injection of trusted server-side data (authenticated user ID)
user_id: req.me.id,
}));-
Sanitization:
req.bodyis replaced by the result ofschema.parse(). Only fields defined in the schema are kept. - Formatting: Zod can transform types (e.g., string to number).
-
Fail fast: if data is invalid, the server immediately returns a
400 Bad Requestwith detailed Zod errors. -
Trusted data: the optional second argument allows "merging" client data with server data (like
req.me.id).
Combining these tools keeps routes and actions extremely clean:
// src/express/modules/item/itemRoutes.ts
itemRoutes.param("itemId", itemParamConverter.convert);
itemRoutes.post("/api/items", itemValidator.validate, itemActions.add);
itemRoutes.put("/api/items/:itemId", itemValidator.validate, itemActions.edit);Thanks to this structure, the edit action can assume that req.item exists and that req.body is perfectly valid and typed:
// src/express/modules/item/itemActions.ts
const edit: RequestHandler = (req, res) => {
const item = { ...req.body, id: req.item.id };
itemRepository.update(item);
res.sendStatus(204);
};- Systematically validate: never trust data sent by the client.
-
Server-side injection: prefer injecting the user ID (
req.me.id) in the validator rather than receiving it from the client. -
Idempotency: the converter returns
204on aDELETEif the resource no longer exists, ensuring that repeated deletions do not cause unnecessary 404 errors.
AI co-creation
Getting started
Explanations
How-To Guides
Reference
Digging deeper