Параметр stopAtFirstError

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

Параметр stopAtFirstError управляет стратегией остановки процесса валидации и позволяет прекратить проверку сразу после обнаружения первой ошибки.


Поведение параметра

stopAtFirstError определяет, будет ли процесс валидации прерываться при первом же нарушении правила.

При значении:

  • false (по умолчанию) — проверяются все свойства и все декораторы, собирается полный массив ошибок
  • true — валидация прекращается сразу после первой обнаруженной ошибки

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


Место применения в API

Параметр передаётся в функцию validate или validateOrReject через объект опций ValidationOptions.

Пример базовой сигнатуры:

validate(object, {
  stopAtFirstError: boolean
})

Поведение при разных сценариях

Обычная валидация без остановки

При стандартной настройке stopAtFirstError: false выполняется полное прохождение по всем правилам:

import { validate } from "class-validator";
import { IsEmail, Length } from "class-validator";

class User {
  @IsEmail()
  email: string;

  @Length(10, 20)
  password: string;
}

const user = new User();
user.email = "invalid";
user.password = "123";

validate(user).then(errors => {
  console.log(errors);
});

Результат содержит ошибки для обоих полей: email и password, даже если первая ошибка уже очевидна.


Остановка при первой ошибке

При включении stopAtFirstError: true процесс завершается при первом нарушении:

validate(user, {
  stopAtFirstError: true,
}).then(errors => {
  console.log(errors);
});

Если ошибка обнаружена в email, проверка password может не выполняться вообще.


Влияние на порядок проверки

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

class Account {
  @Length(5, 10)
  username: string;

  @IsEmail()
  email: string;

  @Length(8, 20)
  password: string;
}

При stopAtFirstError: true:

  1. Проверка начинается с username
  2. При ошибке дальнейшие свойства не анализируются
  3. При отсутствии ошибки переход к следующему свойству

Таким образом, порядок объявления напрямую влияет на результат валидации.


Поведение внутри одного свойства

Каждое свойство может иметь несколько валидаторов:

class Product {
  @IsString()
  @Length(5, 50)
  title: string;
}

При включённом stopAtFirstError:

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

Это снижает количество вычислений, особенно при тяжёлых кастомных валидаторах.


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

Использование stopAtFirstError: true влияет на производительность в больших структурах данных.

Основные эффекты:

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

Особенно заметно при:

  • сложных кастомных валидаторах с запросами к базе данных
  • вложенных структурах DTO с множеством декораторов
  • массовой проверке массивов объектов

Однако оптимизация имеет обратную сторону: отсутствие полного списка ошибок усложняет диагностику входных данных.


Особенности при вложенных объектах

При использовании @ValidateNested() поведение становится менее очевидным.

class Address {
  @Length(10, 50)
  street: string;
}

class User {
  @ValidateNested()
  address: Address;
}

При stopAtFirstError: true:

  • если ошибка возникает в address.street, дальнейшие поля User не проверяются
  • при ошибке на верхнем уровне вложенность может не раскрыться полностью

Это означает, что диагностика сложных структур становится «обрывочной».


Работа с массивами

При валидации массивов объектов:

class Item {
  @IsString()
  name: string;
}

class Order {
  @ValidateNested({ each: true })
  items: Item[];
}

stopAtFirstError: true влияет следующим образом:

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

Это критично в сценариях, где важно собрать полный список некорректных элементов.


Совместимость с skipMissingProperties

При комбинации с skipMissingProperties логика меняется:

  • skipMissingProperties игнорирует undefined
  • stopAtFirstError останавливает выполнение при первой ошибке

Вместе они приводят к максимально «лёгкой» валидации, где проверяется только минимально необходимый набор условий.


Влияние на whitelist и forbidNonWhitelisted

В связке с ValidationOptions:

  • whitelist очищает лишние поля
  • forbidNonWhitelisted выбрасывает ошибку при неизвестных полях

При включённом stopAtFirstError:

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

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

Поведение stopAtFirstError обычно оправдано в случаях:

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

В системах с пользовательским интерфейсом чаще требуется обратный подход — полный список ошибок без прерывания процесса.