Структура объекта ValidationError

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


Базовая форма ValidationError

Каждый экземпляр ValidationError представляет собой объект со следующей логической структурой:

  • информация об исходном объекте
  • имя проверяемого свойства
  • некорректное значение
  • набор нарушенных правил
  • вложенные ошибки (для объектов и массивов)
  • дополнительный контекст валидации

Основные поля ValidationError

target

target: object

Ссылка на исходный объект, который проходил валидацию.

Особенности:

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

Пример смысла:

{
  target: UserDto
}

property

property: string

Имя свойства объекта, в котором обнаружена ошибка.

Особенности:

  • соответствует имени декорированного поля
  • при вложенных объектах относится к текущему уровню (не полному пути)
  • используется совместно с children для построения иерархии

value

value: any

Фактическое значение, которое не прошло проверку.

Особенности:

  • может быть примитивом, объектом, массивом или undefined
  • отражает состояние данных на момент валидации
  • полезно для логирования и диагностики

constraints

constraints?: { [type: string]: string }

Ключевая структура, содержащая описание нарушенных правил валидации.

Формат:

  • ключ — имя валидатора
  • значение — сообщение об ошибке

Пример:

{
  isEmail: "email must be an email",
  isNotEmpty: "email should not be empty"
}

Особенности:

  • один ValidationError может содержать несколько нарушений
  • порядок ключей не гарантируется
  • формируется из декораторов (@IsEmail(), @IsNotEmpty() и т.д.)

children

children: ValidationError[]

Массив вложенных ошибок для объектов и структур с вложенной валидацией.

Используется когда:

  • валидируется объект внутри объекта
  • применяется @ValidateNested()
  • обрабатываются массивы объектов

Структура:

children: [
  ValidationError,
  ValidationError
]

Особенности:

  • формирует дерево ошибок
  • каждый уровень повторяет ту же структуру ValidationError
  • позволяет строить путь до глубоко вложенного поля

Пример иерархии:

user
 └── address
      └── city

contexts

contexts?: { [type: string]: any }

Дополнительные данные, переданные кастомными валидаторами.

Используется в:

  • пользовательских декораторах (ValidatorConstraint)
  • сложных правилах с динамическими параметрами

Особенности:

  • не всегда присутствует
  • структура произвольная
  • зависит от реализации валидатора

Пример:

contexts: {
  minLength: { expected: 5, actual: 3 }
}

Иерархическая модель ошибок

ValidationError строится как дерево:

  • корневой объект содержит ошибки верхнего уровня
  • children раскрывают вложенные структуры
  • каждая ветка повторяет одинаковую модель

Схема:

ValidationError
 ├── property
 ├── constraints
 ├── value
 └── children[]
      └── ValidationError
           └── children[]

Такой подход позволяет:

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

Пример полного объекта ValidationError

Типичная структура результата:

[
  {
    target: {
      email: "test",
      profile: {
        age: -1
      }
    },
    property: "email",
    value: "test",
    constraints: {
      isEmail: "email must be an email"
    },
    children: []
  },
  {
    target: {
      email: "test",
      profile: {
        age: -1
      }
    },
    property: "profile",
    value: {
      age: -1
    },
    constraints: undefined,
    children: [
      {
        property: "age",
        value: -1,
        constraints: {
          min: "age must not be less than 0"
        },
        children: []
      }
    ]
  }
]

Поведение при отсутствующих полях

Если свойство не проходит валидацию на уровне структуры:

  • value может быть undefined
  • constraints содержит ошибки обязательности (isDefined, isNotEmpty)
  • children часто отсутствует

Пример:

{
  property: "password",
  value: undefined,
  constraints: {
    isNotEmpty: "password should not be empty"
  }
}

Отличие корневых и вложенных ошибок

Корневой уровень:

  • содержит ссылку на весь объект
  • описывает поле верхнего уровня DTO

Вложенный уровень:

  • описывает конкретное свойство вложенного объекта
  • не содержит полного пути, только локальное имя

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


Роль constraints в генерации сообщений

constraints формируется на основании активных валидаторов:

  • каждый декоратор добавляет собственный ключ
  • ключи соответствуют внутренним именам валидаторов
  • сообщения могут быть переопределены

Типичный набор:

  • isEmail
  • length
  • min
  • max
  • isNotEmpty
  • matches

Сериализация ValidationError

При преобразовании в JSON:

  • функции отсутствуют
  • сохраняются только данные структуры
  • target может сериализоваться частично в зависимости от содержимого

Результат используется:

  • для API-ответов
  • для логирования
  • для формирования DTO ошибок

Особенности работы с массивами

При валидации массивов:

  • каждый элемент получает собственный ValidationError
  • индекс элемента не хранится напрямую в property
  • вложенность отражается через children

Пример логики:

items -> children[0], children[1]

Поведение при каскадной валидации

При использовании @ValidateNested():

  • создаётся отдельный ValidationError для вложенного объекта
  • он добавляется в children родительского узла
  • структура полностью повторяет дерево DTO

Ключевые свойства модели ValidationError

  • хранит исходные данные через target
  • локализует ошибку через property
  • фиксирует невалидное значение через value
  • агрегирует нарушения через constraints
  • описывает структуру через children
  • расширяется через contexts