Тема замены классического class-validator
на Zod в NestJS зацепила — сам недавно экспериментировал с этим связкой. Делюсь мыслями и болью:
Zod vs class-validator: где границы стираются
- class-validator — это как старый друг: знакомый, предсказуемый, но иногда требует танцев с декораторами:
class CreateUserDto {
@IsString()
@Length(3, 20)
name: string;
}
- Zod же — это валидация через схему, где типы и проверки рождаются в одном месте. Плюс автовывод TypeScript:
const CreateUserSchema = z.object({
name: z.string().min(3).max(20).transform(val => val.trim()),
});
type CreateUserDto = z.infer<typeof CreateUserSchema>;
Никаких двойных объявлений — схема диктует тип.
Интеграция с NestJS: кастомный ValidationPipe
Заменить стандартный pipe на Zod-версию можно так:
import { PipeTransform, Injectable } from '@nestjs/common';
import { ZodSchema } from 'zod';
@Injectable()
export class ZodValidationPipe implements PipeTransform {
constructor(private schema: ZodSchema) {}
transform(value: unknown) {
return this.schema.parse(value); // Выбросит исключение при ошибке
}
}
// В контроллере:
@Post()
@UsePipes(new ZodValidationPipe(CreateUserSchema))
createUser(@Body() dto: CreateUserDto) { /* ... */ }
Или использовать готовые обёртки вроде nestjs-zod
, если лень писать велосипеды.
Кастомные ошибки: от слов к делу
Zod позволяет кастомизировать сообщения глобально или для конкретного поля:
const schema = z.object({
email: z.string().email("Почта выглядит подозрительно 👀"),
});
А потом ловить их в ExceptionFilter NestJS и возвращать клиенту в человекочитаемом виде.
А что с производительностью?
- Для небольших DTO разница незаметна.
- На крупных объектах (100+ полей) Zod слегка просаживается, но это решается кешированием схем.
- Зато Zod даёт возможность парсить сложные структуры (типа union, discriminatedUnion), где
class-validator
требует кастомных декораторов.
Главный вопрос: зачем?
- Если проект уже на
class-validator
— возможно, не стоит ломать. - Если стартуете с нуля или хотите единую схему для клиента и сервера (через tRPC, например) — Zod идеален.