ValidationPipe в NestJS является центральным механизмом
проверки входящих данных. Его поведение определяется набором опций,
которые влияют на трансформацию DTO, обработку ошибок, фильтрацию лишних
полей и стратегию валидации.
Основная конфигурация строится вокруг следующей структуры:
new ValidationPipe({
transform: true,
whitelist: true,
forbidNonWhitelisted: false,
disableErrorMessages: false,
validationError: { target: false },
});
Каждый параметр изменяет поведение пайпа на этапе обработки входящих запросов до попадания данных в контроллер.
Опция transform активирует автоматическое преобразование
plain-объектов в экземпляры классов DTO.
new ValidationPipe({
transform: true,
});
Механизм основан на class-validator и class-transformer,
которые совместно обеспечивают:
Пример поведения:
class CreateUserDto {
name: string;
age: number;
}
При включённом transform:
{ name: "Alex", age: "25" }
становится:
CreateUserDto { name: "Alex", age: 25 }
Это критично для корректной работы числовых и булевых валидаторов.
Опция whitelist удаляет все свойства, не описанные в DTO
через декораторы class-validator.
new ValidationPipe({
whitelist: true,
});
DTO:
class CreateUserDto {
name: string;
}
Вход:
{
"name": "Alex",
"role": "admin"
}
Результат после валидации:
{
"name": "Alex"
}
Механизм опирается на метаданные, которые генерируются декораторами class-validator.
Расширение whitelist — строгий режим обработки входных
данных.
new ValidationPipe({
whitelist: true,
forbidNonWhitelisted: true,
});
В этом режиме наличие лишних свойств приводит не к удалению, а к выбросу исключения.
Поведение:
forbidNonWhitelisted → поле удаляетсяforbidNonWhitelisted → ошибка 400Используется в системах, где важна строгая контрактность API.
Стандартный формат ошибок в NestJS может быть адаптирован через
exceptionFactory.
new ValidationPipe({
exceptionFactory: (errors) => {
const formatted = errors.map(err => ({
field: err.property,
constraints: err.constraints,
}));
return new BadRequestException(formatted);
},
});
Структура ValidationError из class-validator
содержит:
Это позволяет стандартизировать API-ответы под внутренние контракты.
Опция validationError регулирует, какие данные
включаются в ответ:
new ValidationPipe({
validationError: {
target: false,
value: false,
},
});
Параметры:
target — исключает исходный объект DTOvalue — исключает некорректное значениеЭто снижает утечку внутренних данных и уменьшает размер ответа.
Опция позволяет останавливать проверку при первой ошибке:
new ValidationPipe({
stopAtFirstError: true,
});
Поведение:
false — собираются все ошибкиtrue — возвращается только перваяВнутри class-validator это уменьшает количество проходов по цепочке декораторов.
Механизм групп позволяет применять разные правила для разных сценариев.
DTO:
class UserDto {
@IsString({ groups: ['create'] })
name: string;
@IsOptional({ groups: ['update'] })
@IsString()
email?: string;
}
Использование:
new ValidationPipe({
groups: ['create'],
});
Группы позволяют использовать один DTO для разных операций:
Комбинация transform + whitelist является базовой
конфигурацией для строгих API.
new ValidationPipe({
transform: true,
whitelist: true,
});
Результат:
Эта комбинация наиболее тесно связана с корректной работой декораторов class-validator.
При сложных доменных системах стандартный формат ошибок становится недостаточным.
Расширенная трансформация:
function flattenErrors(errors: ValidationError[]) {
return errors.flatMap(err =>
Object.values(err.constraints || {})
);
}
new ValidationPipe({
exceptionFactory: (errors) =>
new BadRequestException({
messages: flattenErrors(errors),
}),
});
Подход применяется для:
class-validator поддерживает глубокую проверку структур через
@ValidateNested.
DTO:
class AddressDto {
@IsString()
city: string;
}
class UserDto {
@ValidateNested()
@Type(() => AddressDto)
address: AddressDto;
}
Для корректной работы требуется:
new ValidationPipe({
transform: true,
});
Без transform вложенные классы не будут корректно
инстанцированы.
Комбинация параметров для максимально строгого режима:
new ValidationPipe({
transform: true,
whitelist: true,
forbidNonWhitelisted: true,
stopAtFirstError: false,
disableErrorMessages: false,
});
Такой режим обеспечивает:
Конфигурация пайпа может быть локальной:
@Post()
@UsePipes(new ValidationPipe({ transform: true }))
create(@Body() dto: CreateUserDto) {}
Локальная настройка имеет приоритет над глобальной, что позволяет адаптировать поведение под конкретные маршруты.
class-validator позволяет создавать пользовательские декораторы:
@ValidatorConstraint({ name: 'isEven', async: false })
export class IsEvenConstraint {
validate(value: number) {
return value % 2 === 0;
}
}
Использование в DTO:
@Validate(IsEvenConstraint)
value: number;
ValidationPipe автоматически учитывает такие правила без дополнительных настроек.
При включённом transform возможны ошибки
преобразования:
Такие ошибки обрабатываются как validation errors внутри пайпа.
Можно контролировать поведение через кастомный exception factory:
exceptionFactory: (errors) => {
return new BadRequestException({
type: 'validation_error',
details: errors,
});
}
Типичные профили использования:
Минимальный режим (разработка):
new ValidationPipe({
whitelist: false,
transform: false,
});
Строгий режим (production):
new ValidationPipe({
transform: true,
whitelist: true,
forbidNonWhitelisted: true,
stopAtFirstError: true,
});
API-first режим:
new ValidationPipe({
transform: true,
whitelist: true,
exceptionFactory: customFormatter,
});
Работа пайпа основана на метаданных, генерируемых декораторами. Без
включённого emitDecoratorMetadata в TypeScript часть
функциональности становится недоступной, особенно:
При масштабировании системы валидации ключевыми становятся:
stopAtFirstError в high-load
сценарияхexceptionFactoryВсе эти механизмы позволяют контролировать поведение ValidationPipe без изменения бизнес-логики контроллеров.