javascript 35 lines · 8 steps

A reusable validation middleware in Express

Turn an express-validator rule schema into a single middleware that validates, formats errors, and exposes clean data.

Explained by highlit
1const { validationResult, matchedData } = require('express-validator');
2 
3function validate(schema) {
4 const runners = schema.map((rule) => rule.run.bind(rule));
5 
6 return async (req, res, next) => {
7 await Promise.all(runners.map((run) => run(req)));
8 
9 const result = validationResult(req);
10 if (!result.isEmpty()) {
11 return res.status(422).json({
12 error: 'ValidationError',
13 details: result.array().map(({ path, msg, value }) => ({
14 field: path,
15 message: msg,
16 value,
17 })),
18 });
19 }
20 
21 req.validated = matchedData(req, { includeOptionals: false });
22 return next();
23 };
24}
25 
26const { body } = require('express-validator');
27 
28const createUserRules = [
29 body('email').trim().isEmail().withMessage('must be a valid email').normalizeEmail(),
30 body('password').isLength({ min: 8 }).withMessage('must be at least 8 characters'),
31 body('displayName').optional().trim().isLength({ max: 60 }).escape(),
32 body('age').optional().isInt({ min: 13, max: 120 }).toInt(),
33];
34 
35module.exports = { validate, createUserRules };
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1A middleware factory lets you configure behavior once and reuse it across many routes.
  2. 2Running all validators with Promise.all validates fields concurrently before checking results.
  3. 3matchedData gives you only the validated, sanitized fields, keeping raw input out of your handlers.

Related explainers

Share this explainer

Here's the card — post it anywhere.

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