Структура сообщений по умолчанию

Библиотека class-validator формирует сообщения об ошибках в строго определённой структуре, которая отражает как сам процесс валидации, так и результаты проверки каждого правила. Основной принцип заключается в том, что каждая ошибка представляет собой объект, содержащий информацию о проверяемом свойстве, значении и наборе нарушенных ограничений.

Базовая структура ValidationError

При провале валидации возвращается массив объектов ValidationError. Каждый объект описывает одно поле или вложенную сущность:

  • property — имя свойства, в котором обнаружена ошибка
  • value — значение, которое не прошло валидацию
  • target — исходный объект, который валидировался
  • constraints — набор нарушенных правил с сообщениями об ошибках
  • children — вложенные ошибки для объектов или массивов
  • contexts — дополнительный контекст (если задан)

Пример типичного объекта:

{
  property: "email",
  value: "invalid-email",
  target: User {
    email: "invalid-email"
  },
  constraints: {
    isEmail: "email must be an email"
  },
  children: []
}

Объект constraints как основа сообщений

Ключевым элементом структуры является поле constraints. Оно представляет собой объект, где:

  • ключ — название декоратора или правила валидации
  • значение — сообщение об ошибке, сформированное библиотекой или заданное разработчиком

Пример:

constraints: {
  isNotEmpty: "username should not be empty",
  length: "username must be longer than or equal to 3 characters"
}

Если на одно поле накладывается несколько ограничений, каждое из них добавляется отдельной записью в constraints. Это позволяет точно определить, какие именно правила были нарушены.

Поведение сообщений по умолчанию

Если разработчик не задаёт собственные сообщения, class-validator использует встроенные шаблоны. Они формируются на основе имени валидатора и параметров декоратора.

Примеры стандартных сообщений:

  • @IsEmail()email must be an email
  • @IsNotEmpty()field should not be empty
  • @Length(3, 10)field must be longer than or equal to 3 and shorter than or equal to 10 characters
  • @IsInt()field must be an integer number

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

Вложенные структуры и children

Поле children используется при работе с вложенными объектами и массивами классов. Оно повторяет структуру ValidationError, но относится к вложенному уровню.

Пример вложенной ошибки:

{
  property: "profile",
  children: [
    {
      property: "age",
      value: -1,
      constraints: {
        min: "age must not be less than 0"
      },
      children: []
    }
  ]
}

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

Поведение при множественных нарушениях

Если одно свойство нарушает несколько правил, все ошибки фиксируются одновременно:

constraints: {
  isNotEmpty: "name should not be empty",
  minLength: "name must be longer than or equal to 2 characters"
}

Порядок ключей в объекте constraints не гарантируется, поскольку он зависит от внутренней реализации JavaScript-объектов и порядка регистрации декораторов.

Контекстные данные (contexts)

Поле contexts используется для передачи дополнительной информации о конкретном ограничении. Оно появляется не всегда и обычно заполняется при использовании кастомных валидаторов.

Пример:

contexts: {
  minLength: {
    constraint: 3,
    value: 1
  }
}

Контекст позволяет не только вывести сообщение, но и использовать дополнительные данные при построении собственных обработчиков ошибок.

Отличие между constraints и message override

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

@IsEmail({}, { message: "Некорректный формат email" })
email: string;

В этом случае структура constraints сохраняется, но значение сообщения заменяется пользовательским текстом:

constraints: {
  isEmail: "Некорректный формат email"
}

Поведение при кастомных валидаторах

При использовании ValidatorConstraint структура остаётся той же, однако ключ в constraints соответствует имени метода validate или имени класса валидатора.

constraints: {
  isEven: "number must be even"
}

Если валидатор возвращает сложную логику проверки, в constraints всё равно фиксируется только итоговое сообщение, без промежуточных состояний.

Особенности сериализации ошибок

При преобразовании ошибок в JSON (например, для API-ответов) структура сохраняется полностью. Однако поля target часто исключаются, чтобы не утяжелять ответ и не раскрывать внутренние данные объекта.

Типичный API-ответ:

[
  {
    "property": "email",
    "value": "invalid",
    "constraints": {
      "isEmail": "email must be an email"
    }
  }
]

Иерархия и рекурсивная природа ошибок

Структура сообщений не является плоской. Она построена как дерево, где каждый узел может содержать:

  • набор собственных нарушений (constraints)
  • вложенные ошибки (children)

Это позволяет корректно обрабатывать сложные DTO, включающие вложенные классы и массивы объектов, сохраняя точную привязку ошибки к исходной структуре данных.