Пошук уроків, статей та іншого контенту
Декларативна перевірка й перетворення вхідних даних до того, як вони дістануться методу контролера.
Без окремого механізму валідації кожен метод контролера довелось би починати з однотипних перевірок вхідних даних — чи є обов'язкові поля, чи правильний тип, чи в допустимому діапазоні значення — і повторювати цю перевірку в кожному місці, де приймаються дані ззовні. Pipe дозволяє винести цю перевірку в окремий, перевикористовуваний, декларативно підключений шар.
Pipe виконується після того, як NestJS витяг значення параметра (через @Body(), @Param() тощо), але до того, як воно дійде до методу контролера — і має одну з двох задач: перевірити дані (і кинути виняток, якщо вони некоректні) або трансформувати їх (наприклад, перетворити рядок параметра маршруту на число).
import { Get, Param, ParseIntPipe } from "@nestjs/common";
@Get(":id")
findOne(@Param("id", ParseIntPipe) id: number) {
// "id" гарантовано вже число — ParseIntPipe кинув би виняток 400 Bad Request,
// якби значення в URL не конвертувалось у число
return this.catsService.findOne(id);
}Для валідації складніших об'єктів (тіло POST/PUT запиту) типовий підхід — описати очікувану форму даних окремим класом (DTO, Data Transfer Object) із декораторами бібліотеки class-validator, а вбудований ValidationPipe перевіряє вхідний об'єкт проти цих правил автоматично:
import { IsString, IsInt, Min } from "class-validator";
export class CreateCatDto {
@IsString()
name: string;
@IsInt()
@Min(0)
age: number;
}
// У контролері:
@Post()
create(@Body(new ValidationPipe()) createCatDto: CreateCatDto) {
return this.catsService.create(createCatDto);
}Якщо клієнт надішле некоректні дані (наприклад, age як від'ємне число), ValidationPipe автоматично поверне 400 Bad Request із детальним описом помилки ще до виклику методу контролера — тілу методу гарантовано дістаються вже валідні дані.
ValidationPipe зазвичай підключають глобально один раз при старті застосунку, а не в кожному методі окремо — так валідація DTO стає узгодженою поведінкою за замовчуванням для всього застосунку:
// main.ts
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe());Дублювати ручні if-перевірки вхідних даних у тілі методу контролера замість Pipes — та сама логіка, яку Pipe виконав би декларативно й перевикористовувано.
Забути декоратори class-validator у DTO-класі — ValidationPipe перевіряє лише те, що описано декораторами; поле без декоратора не валідується взагалі.
Підключати ValidationPipe окремо в кожному контролері замість глобально в main.ts — легко забути для нового контролера, і валідація стає непослідовною по застосунку.
Pipe виконується між отриманням вхідних даних і викликом методу контролера й відповідає за валідацію (перевірка, з можливим винятком) чи трансформацію (перетворення типу) цих даних. ValidationPipe у парі з DTO-класами, описаними декораторами class-validator, — стандартний патерн NestJS для декларативної, перевикористовуваної валідації тіла запиту, зазвичай підключений глобально для всього застосунку.