Что используешь для валидации входящих данных в Express.js?

«Что используешь для валидации входящих данных в Express.js?» — вопрос из категории Express, который задают на 26% собеседований Node.js Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Для валидации в Express.js я предпочитаю связку Joi для описания схем и express-validator для интеграции с middleware. Это дает баланс между мощностью валидации и чистотой кода.

Типичная реализация:

  1. Определение схемы с 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)
      })
    });
  2. 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();
    };
  3. Использование в роуте:

    // 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, создавая отдельные схемы.