Ответ
Для валидации в Express.js я предпочитаю связку Joi для описания схем и express-validator для интеграции с middleware. Это дает баланс между мощностью валидации и чистотой кода.
Типичная реализация:
-
Определение схемы с Joi: Создаю централизованные, переиспользуемые схемы валидации.
// schemas/userSchemas.js const Joi = require('joi'); const createUserSchema = Joi.object({ email: Joi.string().email().required(), password: Joi.string().min(8).pattern(new RegExp('^(?=.*[a-z])(?=.*[A-Z])(?=.*d)')).required(), age: Joi.number().integer().min(18).max(120), preferences: Joi.object({ newsletter: Joi.boolean().default(false) }) }); -
Middleware-обертка для Express: Создаю универсальный валидатор.
// middleware/validate.js const validate = (schema) => (req, res, next) => { const { error, value } = schema.validate(req.body, { abortEarly: false }); // abortEarly: false чтобы получить все ошибки if (error) { const errorMessages = error.details.map(detail => detail.message); return res.status(400).json({ error: 'Validation failed', details: errorMessages }); } // Заменяем req.body на провалидированные и, возможно, кастомизированные данные (например, приведенные типы) req.body = value; next(); }; -
Использование в роуте:
// routes/userRoutes.js const express = require('express'); const router = express.Router(); const { createUserSchema } = require('../schemas/userSchemas'); const validate = require('../middleware/validate'); router.post('/users', validate(createUserSchema), async (req, res) => { // req.body здесь уже гарантированно валиден const newUser = await User.create(req.body); res.status(201).json(newUser); });
Почему такая связка? Joi предоставляет невероятно богатый DSL для описания любых правил, включая кастомные валидации и преобразования типов. express-validator отлично подходит для простых проверок прямо в роуте, но для сложных, вложенных объектов и бизнес-правил Joi выглядит чище и поддерживаемее. Для валидации параметров запроса (req.query, req.params) я также использую Joi, создавая отдельные схемы.