javascript 44 lines · 8 steps

A reusable Zod validation middleware for Express

A factory function turns Zod schemas into Express middleware that validates, coerces, and cleans requests before they reach your handler.

Explained by highlit
1const { z, ZodError } = require('zod');
2 
3function validate(schemas) {
4 return (req, res, next) => {
5 try {
6 if (schemas.body) req.body = schemas.body.parse(req.body);
7 if (schemas.query) req.query = schemas.query.parse(req.query);
8 if (schemas.params) req.params = schemas.params.parse(req.params);
9 next();
10 } catch (err) {
11 if (err instanceof ZodError) {
12 return res.status(422).json({
13 error: 'ValidationError',
14 details: err.issues.map((issue) => ({
15 path: issue.path.join('.'),
16 message: issue.message,
17 })),
18 });
19 }
20 next(err);
21 }
22 };
23}
24 
25const createUserSchema = {
26 body: z.object({
27 email: z.string().email().toLowerCase().trim(),
28 name: z.string().min(1).max(120).trim(),
29 age: z.coerce.number().int().min(18).optional(),
30 role: z.enum(['admin', 'member']).default('member'),
31 tags: z.array(z.string()).default([]),
32 }),
33 query: z.object({
34 notify: z.coerce.boolean().default(false),
35 }),
36};
37 
38router.post('/users', validate(createUserSchema), async (req, res) => {
39 const user = await UserService.create(req.body);
40 if (req.query.notify) await WelcomeMailer.enqueue(user);
41 res.status(201).json(user);
42});
43 
44module.exports = { validate, createUserSchema };
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1A middleware factory lets one validation function serve any route by parameterizing it with schemas.
  2. 2Reassigning req.body to the parse result means coerced and defaulted values flow into your handler, not just the raw input.
  3. 3Catching a specific error type lets you shape client-facing responses while delegating everything else to Express's error pipeline.

Related explainers

Share this explainer

Here's the card — post it anywhere.

A reusable Zod validation middleware for Express — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code