Zod Express Request Validation Middleware
raw JSON →zod-express is an Express.js middleware designed for robust request validation using Zod schemas. Currently at version 0.0.8, this package provides functions like `validateRequest` and `processRequest` to ensure incoming `req.body`, `req.query`, and `req.params` conform to predefined Zod schemas, offering compile-time type safety in TypeScript environments. It recently introduced support for asynchronous validators. `zod-express` is a fork of `zod-express-middleware`, aiming to provide a maintained solution for this use case. Its release cadence appears to be driven by new features or bug fixes, rather than a strict schedule, as indicated by the recent `0.0.8` release adding async validation. Key differentiators include its focus on strong typing with Zod and the flexibility to either just validate or validate and transform/process request data.
Common errors
error TypeError: validateRequest is not a function ↓
import { validateRequest } from 'zod-express'; at the top of your file. If using CommonJS, check your tsconfig.json for "module": "NodeNext" or "type": "module" in package.json. error ZodError: Invalid input ↓
err.errors array within your Express error-handling middleware to get detailed validation messages. Adjust the client-side data or refine your Zod schema to match expected inputs. error Property 'bodyKey' does not exist on type 'Request' ↓
zod-express middleware's type augmentation. Sometimes explicitly casting req or using a generic Request<P, ResBody, ReqBody, ReqQuery> with your schema's inferred type can resolve this, though zod-express aims to handle this automatically. Warnings
breaking As a relatively new package (v0.0.8) forked from another project, the API surface may still be subject to frequent changes and potential breaking modifications between minor or even patch versions. Exercise caution when upgrading. ↓
gotcha The validation middlewares (`validateRequest`, `validateRequestBody`, etc.) will throw a `ZodError` if validation fails. Without an Express error-handling middleware, this can lead to unhandled promise rejections or generic server errors. ↓
gotcha The `processRequest` (and related `processRequestBody`, etc.) functions will apply Zod transformations (`.transform()`) to the request data. This means `req.body`, `req.query`, or `req.params` might be modified, which can be unexpected if you only intended to validate. ↓
Install
npm install zod-express yarn add zod-express pnpm add zod-express Imports
- validateRequest wrong
const { validateRequest } = require('zod-express');correctimport { validateRequest } from 'zod-express'; - validateRequestAsync wrong
import validateRequestAsync from 'zod-express';correctimport { validateRequestAsync } from 'zod-express'; - processRequest wrong
import { validateRequest } from 'zod-express/process';correctimport { processRequest } from 'zod-express'; - z
import { z } from 'zod';
Quickstart
import express from 'express';
import { validateRequest } from 'zod-express';
import { z } from 'zod';
// Create an express app
const app = express();
app.use(express.json()); // Essential for parsing JSON bodies
// Define an endpoint using express, zod and zod-express
app.get("/:urlParameter/", validateRequest({
params: z.object({
urlParameter: z.string(),
}),
body: z.object({
bodyKey: z.number(),
}),
query: z.object({
queryKey: z.string().length(64),
}),
}), (req, res) => {
// req.params, req.body and req.query are now strictly-typed and confirm to the zod schema's above.
// req.params has type { urlParameter: string };
// req.body has type { bodyKey: number };
// req.query has type { queryKey: string };
return res.json({message: "Validation for params, body and query passed", data: { params: req.params, body: req.body, query: req.query }});
}
);
// Add a basic error handling middleware to catch ZodErrors
app.use((err, req, res, next) => {
if (err instanceof z.ZodError) {
return res.status(400).json({ error: 'Validation failed', details: err.errors });
}
next(err);
});
// Start the express app on port 8080
const PORT = 8080;
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});