Skip to main content
Practice Problems

How to validate request data in Express.js?

Request Validation in Express.js

Never trust client input. Validating and sanitizing request data (body, params, query) before processing it is a critical security and reliability practice.


Option 1: Zod (TypeScript-first)

bash
npm install zod
js
const { z } = require('zod'); // Define schema const createUserSchema = z.object({ body: z.object({ name: z.string().min(2).max(50), email: z.string().email(), age: z.number().int().min(18).max(120).optional(), role: z.enum(['user', 'admin']).default('user'), }) }); // Reusable validation middleware function validate(schema) { return (req, res, next) => { try { schema.parse({ body: req.body, query: req.query, params: req.params, }); next(); } catch (err) { const errors = err.errors.map(e => ({ field: e.path.join('.'), message: e.message })); res.status(400).json({ error: 'Validation failed', details: errors }); } }; } // Use in routes app.post('/users', validate(createUserSchema), asyncHandler(async (req, res) => { const user = await usersService.create(req.body); res.status(201).json({ data: user }); }) );

Option 2: express-validator

bash
npm install express-validator
js
const { body, param, query, validationResult } = require('express-validator'); // Validation rules const createUserRules = [ body('name').trim().isLength({ min: 2, max: 50 }).withMessage('Name must be 2-50 chars'), body('email').isEmail().normalizeEmail().withMessage('Invalid email'), body('age').optional().isInt({ min: 18 }).withMessage('Must be 18+'), body('password').isStrongPassword().withMessage('Password too weak'), ]; // Collect and return errors function checkValidation(req, res, next) { const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).json({ error: 'Validation failed', details: errors.array() }); } next(); } app.post('/users', createUserRules, checkValidation, createUser);

Validating URL Parameters & Query Strings

js
const getUserRules = [ param('id').isInt({ min: 1 }).withMessage('ID must be a positive integer'), ]; const listUsersRules = [ query('page').optional().isInt({ min: 1 }).default(1), query('limit').optional().isInt({ min: 1, max: 100 }).default(10), query('sort').optional().isIn(['name', 'email', 'createdAt']), ]; app.get('/users', listUsersRules, checkValidation, getUsers); app.get('/users/:id', getUserRules, checkValidation, getUser);

Option 3: Joi

bash
npm install joi
js
const Joi = require('joi'); const createUserSchema = Joi.object({ name: Joi.string().min(2).max(50).required(), email: Joi.string().email().required(), password: Joi.string().min(8).required(), role: Joi.string().valid('user', 'admin').default('user'), }); function validate(schema) { return (req, res, next) => { const { error, value } = schema.validate(req.body, { abortEarly: false }); if (error) { const details = error.details.map(d => d.message); return res.status(400).json({ error: 'Validation failed', details }); } req.body = value; // use sanitized/typed value next(); }; }

Comparison

LibraryStyleTypeScriptBundle Size
ZodSchema-first, TypeScript-nativeExcellentMedium
express-validatorChain API, Express-nativeGoodSmall
JoiSchema-first, Hapi-originGoodMedium

Summary

Always validate: body, params, and query before processing. Use a middleware pattern for clean, reusable validation. Zod is recommended for TypeScript projects for end-to-end type safety. Return 400 Bad Request with details when validation fails.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.

Finished reading?
Practice Problems