Ответ
Для валидации в 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, создавая отдельные схемы.
Ответ 18+ 🔞
А, валидация в Экспрессе! Ну тут, блядь, история как с выбором тачки — можно на жигулях ездить, а можно сразу на чём-то с турбиной. Я вот, например, предпочитаю связку Joi для описания правил и express-validator для встраивания в мидлварь. Получается, ёпта, идеальный баланс: мощь валидации и при этом код не превращается в пиздопроебибну.
Как я это обычно делаю, смотри:
-
Схемы на 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) }) }); -
Универсальный валидатор-мидлварь: Делаю одну функцию, которая принимает схему и дальше сама всё ебёт-колотит. Главное —
abortEarly: false, чтобы получить сразу все косяки, а не по одному, а то терпения ноль ебать.// 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(); }; -
Применение в роуте: И вот тут уже красота. Подключаешь мидлварь, и в хендлер попадает уже гарантированно чистый
req.body. Никаких сюрпризов.// 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 — это просто песня, ебать мои старые костыли. Там можно описать вообще любую, даже самую хитрожопую логику валидации, с кастомными правилами и преобразованиями. express-validator хорош для простых проверок прямо в цепочке роута, но когда у тебя объекты вложенные, с кучей условий — Joi выглядит в разы чище и надёжнее. Для req.query и req.params я тоже Joi юзаю, просто отдельные схемы пишу. В общем, доверия к этому подходу — не ноль, а вполне себе овердохуища.