Валидация данных в class-validator часто используется в
связке с преобразованием входящих объектов через
class-transformer и последующей проверкой экземпляров
классов. Одной из ключевых проблем при работе с внешними данными
является попадание в систему «чужих» значений — объектов, которые не
соответствуют ожидаемой структуре, но всё равно проходят через пайп
валидации из-за особенностей JavaScript-типизации.
Параметр forbidUnknownValues решает именно эту проблему,
заставляя валидатор строго отклонять любые значения, которые не являются
валидируемыми экземплярами классов или не содержат метаданных
валидации.
forbidUnknownValuesПараметр используется в глобальной конфигурации
ValidationOptions и управляет поведением при получении
значений, которые не были явно описаны через декораторы
class-validator.
Основная задача:
Запретить обработку “сырых” объектов, не прошедших трансформацию в экземпляры классов или не содержащих метаданных валидации.
Это особенно важно в архитектурах, где данные приходят извне (HTTP, очереди сообщений, WebSocket), и требуется строгая типизация на уровне исполнения.
Без включённого forbidUnknownValues валидатор допускает
любые объекты, даже если они не являются экземплярами классов:
import { validate } from 'class-validator';
class User {
name: string;
}
const plainObject = { name: 'Alex' };
validate(plainObject as any).then(errors => {
console.log(errors);
});
В этом случае class-validator не способен распознать
структуру как валидируемую сущность, но и не выбрасывает ошибку, а
просто возвращает пустой массив ошибок.
forbidUnknownValuesПри активации параметра поведение становится строгим:
import { validate } from 'class-validator';
validate(someObject, {
forbidUnknownValues: true,
});
Теперь любые объекты, которые:
class-validatorбудут считаться недопустимыми.
Внутри class-validator используется проверка наличия
метаданных, связанных с классом. Если объект не содержит этих
метаданных, он классифицируется как «неизвестное значение».
При forbidUnknownValues: true происходит следующее:
Если передан объект без метаданных, результат содержит специальную ошибку:
[
{
target: { ... },
property: undefined,
constraints: {
unknownValue: 'an unknown value was passed to validation'
}
}
]
Это означает, что валидация не была выполнена на уровне полей, поскольку сам объект не признан валидным.
class-transformerНа практике forbidUnknownValues почти всегда
используется вместе с class-transformer, так как именно
трансформация создаёт корректные экземпляры классов:
import { plainToInstance } from 'class-transformer';
import { validate } from 'class-validator';
class User {
name: string;
}
const plain = { name: 'Alex' };
const instance = plainToInstance(User, plain);
validate(instance, { forbidUnknownValues: true });
Если plainToInstance не используется, или используется
некорректно, включённый forbidUnknownValues приведёт к
ошибке даже при корректной структуре объекта.
При обработке HTTP-запросов:
@Post()
create(@Body() dto: CreateUserDto) {
return this.service.create(dto);
}
Если пайп валидации настроен с
forbidUnknownValues: true, любые объекты, не приведённые к
DTO-классу, будут отклонены.
Без строгого режима можно передать объект:
{
anyField: 'value',
injected: true
}
и он может пройти дальше, если не проверяется структура.
forbidUnknownValues блокирует подобные случаи, если объект
не соответствует классу.
Если данные не проходят через plainToInstance, даже
валидные структуры будут отклонены.
Параметр работает на уровне объекта, а не отдельных свойств. Если объект признан валидным, дальнейшая валидация происходит отдельно.
При работе с временными структурами (например, частично собранными объектами) параметр может приводить к неожиданным ошибкам.
whitelistforbidUnknownValues часто путают с
whitelist, однако их поведение различается:
whitelist удаляет неизвестные свойства внутри валидного
объектаforbidUnknownValues отклоняет весь объект целиком, если
он не соответствует классуКомбинация:
validate(obj, {
whitelist: true,
forbidNonWhitelisted: true,
forbidUnknownValues: true,
});
создаёт строгий режим, при котором:
Можно выделить три уровня обработки входных данных:
whitelist — очищаются лишние поля,
но структура может быть слабойforbidUnknownValues — валидируются
только корректно созданные DTO-экземплярыЧасто встречающаяся проблема:
const dto = JSON.parse(request.body);
validate(dto, { forbidUnknownValues: true });
Ошибка возникает потому, что dto — обычный объект, не
связанный с классом. В таких случаях необходимо явно создавать экземпляр
класса через трансформацию или конструктор.
При вложенных DTO параметр проверяется только на верхнем уровне объекта. Вложенные структуры валидируются уже после подтверждения корректности корневого объекта.
class Profile {
age: number;
}
class User {
profile: Profile;
}
Если User не является валидным экземпляром, валидация
profile не выполняется вообще.
Использование forbidUnknownValues фактически задаёт
правило:
валидируются только объекты, созданные через контролируемый процесс трансформации
Это приводит к архитектурному следствию:
При включении строгих настроек:
{
forbidUnknownValues: true,
whitelist: true,
forbidNonWhitelisted: true
}
валидация превращается в фильтр, который допускает только:
Любое отклонение приводит к немедленному отклонению объекта до проверки его полей.