Node.js7 min read
Input Validation with express-validator
Validate and sanitize user input in Express. Prevent security issues and ensure data integrity.
Sarah Chen
December 19, 2025
0.0k0
Input Validation with express-validator
Never trust user input. Validate everything.
Setup
npm install express-validator
Basic Validation
const { body, validationResult } = require('express-validator');
app.post('/api/users',
body('email').isEmail(),
body('password').isLength({ min: 6 }),
(req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
// Validation passed
res.json({ message: 'User created' });
}
);
Common Validators
body('email').isEmail(),
body('password').isLength({ min: 6, max: 100 }),
body('age').isInt({ min: 0, max: 120 }),
body('price').isFloat({ min: 0 }),
body('website').isURL(),
body('phone').isMobilePhone(),
body('date').isISO8601(),
body('uuid').isUUID(),
body('role').isIn(['user', 'admin']),
body('tags').isArray(),
body('name').notEmpty(),
body('bio').optional().isLength({ max: 500 }),
Custom Error Messages
body('email')
.isEmail()
.withMessage('Please enter a valid email'),
body('password')
.isLength({ min: 6 })
.withMessage('Password must be at least 6 characters'),
Sanitization
body('email').normalizeEmail(),
body('name').trim().escape(),
body('age').toInt(),
body('price').toFloat(),
body('tags').toArray(),
Chaining Validators
body('password')
.trim()
.isLength({ min: 8 })
.withMessage('Password must be at least 8 characters')
.matches(/[A-Z]/)
.withMessage('Must contain uppercase letter')
.matches(/[0-9]/)
.withMessage('Must contain number'),
Custom Validators
body('confirmPassword').custom((value, { req }) => {
if (value !== req.body.password) {
throw new Error('Passwords do not match');
}
return true;
}),
body('email').custom(async (email) => {
const user = await User.findOne({ email });
if (user) {
throw new Error('Email already in use');
}
}),
Validating Params & Query
const { param, query } = require('express-validator');
// Route params
app.get('/api/users/:id',
param('id').isMongoId(),
(req, res) => { ... }
);
// Query strings
app.get('/api/search',
query('q').notEmpty().trim(),
query('page').optional().isInt({ min: 1 }),
query('limit').optional().isInt({ min: 1, max: 100 }),
(req, res) => { ... }
);
Reusable Validation Middleware
// validations/user.js
const { body } = require('express-validator');
const createUserValidation = [
body('name')
.trim()
.notEmpty()
.withMessage('Name is required')
.isLength({ max: 100 }),
body('email')
.isEmail()
.normalizeEmail()
.withMessage('Valid email required'),
body('password')
.isLength({ min: 8 })
.withMessage('Password must be 8+ characters')
];
const updateUserValidation = [
body('name').optional().trim().isLength({ max: 100 }),
body('email').optional().isEmail().normalizeEmail()
];
module.exports = { createUserValidation, updateUserValidation };
Validation Middleware
// middleware/validate.js
const { validationResult } = require('express-validator');
const validate = (req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({
status: 'error',
errors: errors.array().map(err => ({
field: err.path,
message: err.msg
}))
});
}
next();
};
module.exports = validate;
Complete Example
const { createUserValidation } = require('./validations/user');
const validate = require('./middleware/validate');
app.post('/api/users',
createUserValidation,
validate,
async (req, res) => {
// All validation passed
const user = await User.create(req.body);
res.status(201).json(user);
}
);
Key Takeaway
Always validate user input. Use express-validator for declarative validation. Sanitize data to prevent XSS. Create reusable validation arrays. Return clear error messages. It's your first line of defense against bad data.
#Node.js#Express#Validation#Security#Intermediate