Chapter 2 · Practice 1 of 4
Validate the body, params, query and headers of every request
Why it matters
Everything in a request is untrusted: body, path params, query string, headers and cookies. Validate each one against a schema before your code uses it.
A good schema does three things:
- Rejects unknown fields.
- Enforces types, coercing query strings, which always arrive as text.
- Sets limits on string lengths, array sizes and number ranges.
Where the validation lives depends on the framework:
- Express: parse with a library such as Zod at the top of each handler or in a small middleware.
- Fastify: JSON Schema validation is built into its route options, which also speeds up serialization.
On failure, return a 400 with field-level messages so clients can fix their request.
Do
- Use
safeParseand turn failures into a 400 with a list of field errors - Coerce and validate query strings, which always arrive as text
Avoid
- Passing
req.bodystraight into a database query or update
Example
const createUser = z.object({
email: z.email().max(254),
name: z.string().trim().min(1).max(80),
});
app.post('/users', async (req, res) => {
const result = createUser.safeParse(req.body);
if (!result.success) return res.status(400).json({ errors: result.error.issues });
res.status(201).json(await users.create(result.data));
});