HossamMohsen7/zod-express-validator(opens in a new tab)
Language: TypeScript
A NodeJS package to validate Express request and response payloads using Zod.
- stars
- 7
- watchers
- 2
- forks
- 1
- open issues
- 0
- Last updated
- 05/28/2026
Language: TypeScript
A NodeJS package to validate Express request and response payloads using Zod.
A package to validate Express request and response payloads using Zod.
Inspired by zod-express-middleware
| Peer dependency | Version |
|---|---|
express |
^5.0.0 |
zod |
^4.0.0 |
npm install zod-express-validator # or yarn add zod-express-validator # or pnpm add zod-express-validator
Pass validate(schemas, onError?) as a middleware. The next handler receives a fully typed req — no casts needed.
import express from "express"; import z from "zod"; import { validate } from "zod-express-validator"; const app = express(); app.use(express.json()); const bodySchema = z.object({ name: z.string().min(3).max(255), }); const paramsSchema = z.object({ userId: z.coerce.number(), }); const querySchema = z.object({ page: z.coerce.number().min(1).max(100), }); const responseSchema = z.object({ success: z.boolean(), }); app.post( "/info/:userId", validate( { body: bodySchema, params: paramsSchema, query: querySchema, res: responseSchema, }, ({ bodyError, paramsError, queryError }, res) => { const error = bodyError ?? paramsError ?? queryError; return res.status(400).json({ error: error?.message }); }, ), (req, res) => { const body = req.body; // { name: string } const params = req.params; // { userId: number } const query = req.query; // { page: number } // res.json is type-checked against responseSchema return res.status(200).json({ success: true }); }, );
Note: Any schema can be omitted if you don't need to validate that part of the request.
Important: Forparamsandquery, always usez.coerce— these values arrive as strings from the URL.
Extract the validator to a variable and derive the controller type from it using TypedRequestHandler. This keeps schemas, middleware, and controller all in sync from a single declaration.
import express from "express"; import z from "zod"; import { validate, TypedRequestHandler } from "zod-express-validator"; const app = express(); app.use(express.json()); const bodySchema = z.object({ name: z.string().min(3).max(255), }); const paramsSchema = z.object({ userId: z.coerce.number(), }); const querySchema = z.object({ page: z.coerce.number().min(1).max(100), }); const responseSchema = z.object({ success: z.boolean(), }); const validator = validate( { body: bodySchema, params: paramsSchema, query: querySchema, res: responseSchema, }, ({ bodyError, paramsError, queryError }, res) => { const error = bodyError ?? paramsError ?? queryError; return res.status(400).json({ error: error?.message }); }, ); const controller: TypedRequestHandler<typeof validator> = (req, res) => { const body = req.body; // { name: string } const params = req.params; // { userId: number } const query = req.query; // { page: number } return res.status(200).json({ success: true }); }; app.post("/info/:userId", validator, controller);
If validation fails, the onZodErrors callback is called with a ValidationError containing the errors for each part of the request.
If no callback is provided, a RequestValidationError is forwarded to next() for Express's error-handling middleware to process:
app.use((err, req, res, next) => { if (err instanceof RequestValidationError) { const { paramsError, queryError, bodyError } = err.errors; return res.status(400).json({ paramsError, queryError, bodyError }); } next(err); });
Returns a Validator<T> middleware that validates the request before passing control to the next handler.
| Parameter | Type | Description |
|---|---|---|
schemas |
Schemas |
Zod schemas for params, query, body, and/or res. |
onZodErrors |
(errors: ValidationError, res: Response) => Response | never |
Optional. Called on validation failure. Omit to forward a RequestValidationError to next. |
| Type | Description |
|---|---|
Schemas |
Shape of the object passed to validate(). All fields are optional. |
Validator<T> |
Return type of validate(). Extends RequestHandler and carries the schema type for inference. |
TypedRequestHandler<T> |
Type for a controller derived from a Validator<T> or a Schemas object. |
TypedRequest<T> |
A typed Request with params, body, and query replaced by their Zod-inferred types. |
InferSchemas<T> |
Utility type that extracts the inferred params / query / body / res types from a Schemas. |
ValidationError |
Object containing paramsError?, queryError?, bodyError? as ZodError instances. |
RequestValidationError |
Error subclass forwarded to next() when no onZodErrors is provided. Contains .errors. |
This package uses SemVer for versioning. See CHANGELOG.md and BREAKING_CHANGES.md for version history.
Feel free to open an issue or a pull request if you have any suggestions or if you found a bug.
This project is licensed under the MIT License - see the LICENSE file for details.