Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Валидация: ValidationPipe и class-validator

Валидация — проверка того, что клиент прислал правильные данные: заголовок есть, это строка, длина в допустимых пределах. В NestJS правила записывают декораторами прямо в DTO, а проверку выполняет встроенный ValidationPipe. При ошибке клиент получает ответ 400 со списком проблем, и метод контроллера даже не вызывается.

Установка

npm i class-validator class-transformer

class-validator содержит декораторы правил, class-transformer превращает обычный JSON в объект класса DTO, чтобы эти правила можно было проверить.

Правила в DTO

// src/posts/dto/create-post.dto.ts
import { IsNotEmpty, IsString, MaxLength } from 'class-validator';
 
export class CreatePostDto {
  @IsString()
  @IsNotEmpty()
  @MaxLength(120)
  title: string;
 
  @IsString()
  @IsNotEmpty()
  content: string;
}

Каждое поле получило правила: строка, не пустая, а заголовок ещё и не длиннее 120 символов.

Включение ValidationPipe

Пайп включают для всего приложения в src/main.ts:

// src/main.ts
import { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
 
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(new ValidationPipe({ whitelist: true }));
  await app.listen(process.env.PORT ?? 3000);
}
bootstrap();

Теперь каждый аргумент с @Body(), тип которого — класс с правилами, проверяется перед вызовом метода. Отправьте статью без заголовка:

curl -X POST http://localhost:3000/posts \
  -H "Content-Type: application/json" \
  -d '{"content":"Текст без заголовка"}'

Сервер ответит кодом 400 и списком нарушенных правил:

{
  "message": [
    "title must be shorter than or equal to 120 characters",
    "title should not be empty",
    "title must be a string"
  ],
  "error": "Bad Request",
  "statusCode": 400
}

Свой текст ошибки задают в последнем аргументе правила: @IsNotEmpty({ message: 'Укажите заголовок' }).

Частые правила

ДекораторЧто проверяет
@IsString()Строка
@IsInt()Целое число
@IsEmail()Адрес электронной почты
@IsNotEmpty()Не пустая строка, не null и не undefined
@MinLength(8)Строка не короче 8 символов
@MaxLength(120)Строка не длиннее 120 символов
@IsOptional()Поле можно не передавать
@IsIn(['draft', 'published'])Одно из перечисленных значений

Настройки пайпа

ПараметрЧто делает
whitelist: trueУдаляет из тела поля, которых нет в DTO
forbidNonWhitelisted: trueВместо удаления отвечает ошибкой 400
transform: trueПередаёт в метод объект класса DTO и приводит типы параметров

whitelist защищает от лишних полей: если клиент пришлёт "role":"admin", это поле не дойдёт до сервиса.

Частая ошибка

Правила не срабатывают, если тип аргумента — интерфейс или any: пайпу не с чем сравнивать данные. То же случится, если забыть app.useGlobalPipes(...) — запрос с пустым телом спокойно дойдёт до сервиса. Проверяйте работу валидации заведомо плохим запросом сразу после её подключения.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.