Параметр forbidUnknownValues

Валидация данных в 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 происходит следующее:

  1. Проверяется тип значения.
  2. Определяется наличие метаданных валидации.
  3. Если метаданных нет — генерируется ошибка валидации.
  4. Дальнейшие проверки свойств не выполняются.

Поведение при ошибке

Если передан объект без метаданных, результат содержит специальную ошибку:

[
  {
    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 приведёт к ошибке даже при корректной структуре объекта.


Типичные сценарии использования

Защита API от «лишних» объектов

При обработке HTTP-запросов:

@Post()
create(@Body() dto: CreateUserDto) {
  return this.service.create(dto);
}

Если пайп валидации настроен с forbidUnknownValues: true, любые объекты, не приведённые к DTO-классу, будут отклонены.


Предотвращение обхода схемы валидации

Без строгого режима можно передать объект:

{
  anyField: 'value',
  injected: true
}

и он может пройти дальше, если не проверяется структура. forbidUnknownValues блокирует подобные случаи, если объект не соответствует классу.


Ограничения и особенности

1. Требует корректной трансформации

Если данные не проходят через plainToInstance, даже валидные структуры будут отклонены.

2. Не проверяет поля

Параметр работает на уровне объекта, а не отдельных свойств. Если объект признан валидным, дальнейшая валидация происходит отдельно.

3. Может конфликтовать с «сырыми» объектами

При работе с временными структурами (например, частично собранными объектами) параметр может приводить к неожиданным ошибкам.


Взаимодействие с whitelist

forbidUnknownValues часто путают с whitelist, однако их поведение различается:

  • whitelist удаляет неизвестные свойства внутри валидного объекта
  • forbidUnknownValues отклоняет весь объект целиком, если он не соответствует классу

Комбинация:

validate(obj, {
  whitelist: true,
  forbidNonWhitelisted: true,
  forbidUnknownValues: true,
});

создаёт строгий режим, при котором:

  • неизвестные поля запрещены
  • невалидные объекты отклоняются полностью

Практическая модель поведения

Можно выделить три уровня обработки входных данных:

  1. Без строгих опций — любые объекты проходят, ошибки обнаруживаются частично
  2. С whitelist — очищаются лишние поля, но структура может быть слабой
  3. С 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 фактически задаёт правило:

валидируются только объекты, созданные через контролируемый процесс трансформации

Это приводит к архитектурному следствию:

  • входные данные всегда должны быть приведены к DTO
  • любые «сырые» структуры считаются недопустимыми
  • система становится более предсказуемой, но менее гибкой

Поведение в режиме строгой типизации

При включении строгих настроек:

{
  forbidUnknownValues: true,
  whitelist: true,
  forbidNonWhitelisted: true
}

валидация превращается в фильтр, который допускает только:

  • экземпляры классов с метаданными
  • строго описанные DTO
  • полностью соответствующие структуры без лишних свойств

Любое отклонение приводит к немедленному отклонению объекта до проверки его полей.