Перейти к основному содержимому

Декораторы валидации

Express-Cargo использует декораторы для валидации входящих данных запроса, которые привязываются к классу.

Валидация не выполняется отдельной функцией validate. Вместо этого она интегрирована в промежуточное ПО bindingCargo, которое автоматически валидирует данные во время жизненного цикла запроса.

Встроенные валидаторы

@Optional()

Помечает поле как необязательное, позволяя его опустить или установить в undefined без вызова ошибок валидации.

@Min(value: number)

Проверяет, что число больше или равно указанному минимальному значению.

  • value: Минимально допустимое значение.

@Max(value: number)

Проверяет, что число меньше или равно указанному максимальному значению.

  • value: Максимально допустимое значение.

@Range(min: number, max: number)

Проверяет, что число находится в указанном диапазоне, включая минимальное и максимальное значения.

  • min: Минимально допустимое значение.
  • max: Максимально допустимое значение.

@Contains(seed: string)

Проверяет, что строка содержит указанную подстроку.

  • seed: Подстрока, которая должна присутствовать в строке.
  • message (необязательно): Сообщение об ошибке, отображаемое при неудачной валидации. Если не указано, используется сообщение по умолчанию.

@Prefix(value: string)

Проверяет, что строка начинается с указанного префикса.

  • value: Требуемый начальный текст.

@Suffix(value: string)

Проверяет, что строка заканчивается указанным суффиксом.

  • value: Требуемый конечный текст.

@Equal(value: any)

Проверяет, что значение строго равно (===) указанному значению.

  • value: Значение для сравнения.

@NotEqual(value: any)

Проверяет, что значение строго не равно (!==) указанному значению.

  • value: Значение для сравнения.

@IsTrue()

Проверяет, что декорированное свойство истинно (true).

@IsFalse()

Проверяет, что декорированное свойство ложно (false).

@Length(value: number)

Проверяет, что длина декорированной строки точно равна указанному значению.

  • value: Требуемая точная длина в символах.

@MaxLength(value: number)

Проверяет, что длина декорированной строки не превышает указанный максимум.

  • value: Максимально допустимая длина в символах.

@MinLength(value: number)

Проверяет, что длина декорированной строки не меньше указанного минимума.

  • value: Минимально допустимая длина в символах.

@OneOf(values: any[])

Проверяет, что входное значение является одним из указанных значений.

  • values: Массив допустимых значений.

@ListContains(values: any[], comparator?: (expected, actual) => boolean, message?: string)

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

  • values: Значения, которые должны присутствовать в массиве.
  • comparator (необязательно): Пользовательская функция сравнения (expected, actual) => boolean. Если указана, все сравнения делегируются этой функции, включая примитивы.
  • message (необязательно): Сообщение об ошибке, отображаемое при неудачной валидации. Если не указано, будет использовано сообщение по умолчанию.

Предупреждение: Сравнение объектов по умолчанию использует глубокое равенство. Производительность может снизиться, если values содержит много объектов или глубоко вложенные структуры. Рассмотрите использование comparator для более эффективного или гибкого сравнения.

@ListNotContains(values: any[], comparator?: (expected, actual) => boolean, message?: string)

Проверяет, что массив НЕ содержит ни одного из указанных значений. Поддерживает примитивные значения, объекты, Date и смешанные типы.

  • values: Значения, которые НЕ должны присутствовать в массиве.
  • comparator (необязательно): Пользовательская функция сравнения (expected, actual) => boolean. Если указана, все сравнения делегируются этой функции, включая примитивы.
  • message (необязательно): Сообщение об ошибке, отображаемое при неудачной валидации. Если не указано, будет использовано сообщение по умолчанию.

Предупреждение: Сравнение объектов по умолчанию использует глубокое равенство. Производительность может снизиться, если values содержит много объектов или глубоко вложенные структуры. Рассмотрите использование comparator для более эффективного или гибкого сравнения.

@Enum(enumObj: object, message?: string)

Проверяет, что входное значение соответствует одному из значений в указанном объекте перечисления. Также автоматически преобразует входное значение (например, строковый ключ) в соответствующее значение перечисления.

  • enumObj: Объект перечисления для валидации.
  • message (необязательно): Сообщение об ошибке, которое будет отображаться при сбое валидации. Если опущено, будет использоваться сообщение по умолчанию.

@Validate(validateFn: (value: unknown) => boolean, message?: string)

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

  • validateFn: Функция, которая получает значение поля и возвращает true, если оно валидно, и false в противном случае.
  • message (необязательно): Сообщение об ошибке, которое будет отображаться при сбое валидации. Если опущено, будет использоваться сообщение по умолчанию.

@Regexp(pattern: RegExp, message?: string)

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

  • pattern: Объект RegExp, используемый для проверки значения поля. Значение считается валидным, если оно соответствует шаблону.
  • message (необязательно): Сообщение об ошибке, которое будет отображаться при сбое валидации. Если опущено, будет использоваться сообщение по умолчанию.

@Email()

Проверяет, что декорированное свойство является действительным адресом электронной почты.

@Alpha(message?: string)

Проверяет, что декорированное поле содержит только алфавитные символы (прописные или строчные английские буквы, A–Z / a–z).

  • message (необязательно): Сообщение об ошибке, которое будет отображаться при сбое валидации. Если опущено, будет использоваться сообщение по умолчанию.

@Uuid(version?: 'v1' | 'v3' | 'v4' | 'v5', message?: string)

Проверяет, что декорированное поле является действительной строкой UUID, опционально ограниченной определенной версией (v1, v3, v4 или v5).

  • version (необязательно): Конкретная версия UUID для проверки. Если опущено, проверяется на соответствие v1, v3, v4 или v5.
  • message (необязательно): Сообщение об ошибке, которое будет отображаться при сбое валидации. Если опущено, будет использоваться сообщение по умолчанию.

@Alphanumeric(message?: string)

Проверяет, что декорированное поле содержит только буквенно-цифровые символы (английские буквы и цифры, A–Z, a–z, 0–9).

  • message (необязательно): Сообщение об ошибке, которое будет отображаться при сбое валидации. Если опущено, будет использоваться сообщение по умолчанию.

@IsUppercase(message?: string)

Проверяет, что декорированное поле содержит только символы верхнего регистра.

  • message (необязательно): Сообщение об ошибке, которое будет отображаться при сбое валидации. Если опущено, будет использоваться сообщение по умолчанию.

@IsLowercase(message?: string)

Проверяет, что декорированное поле содержит только символы нижнего регистра.

  • message (необязательно): Сообщение об ошибке, которое будет отображаться при сбое валидации. Если опущено, будет использоваться сообщение по умолчанию.

@IsJwt(message?: string)

Проверяет, что декорированное поле соответствует формату JWT (header.payload.signature). Каждая часть должна состоять из символов Base64URL (A-Z, a-z, 0-9, -, _). Декоратор проверяет только формат — подпись и валидность токена не проверяются.

  • message (необязательно): Сообщение об ошибке, которое будет отображаться при сбое валидации. Если опущено, будет использоваться сообщение по умолчанию.

@IsUrl(options?: IsUrlOptions, message?: string)

Проверяет, что декорированное поле является допустимым URL. По умолчанию разрешены протоколы http, https и ftp.

  • options (необязательно):
    • protocols: Массив разрешённых протоколов. По умолчанию: ['http', 'https', 'ftp'].
  • message (необязательно): Сообщение об ошибке, которое будет отображаться при сбое валидации. Если опущено, будет использоваться сообщение по умолчанию.

@IsHexColor(message?: string)

Проверяет, что декорированное поле является допустимым шестнадцатеричным кодом цвета. Поддерживаются форматы #RGB, #RGBA, #RRGGBB и #RRGGBBAA (без учёта регистра). Префикс # обязателен.

  • message (необязательно): Сообщение об ошибке, которое будет отображаться при сбое валидации. Если опущено, будет использоваться сообщение по умолчанию.

@IsHexadecimal(message?: string)

Проверяет, что декорированное поле является шестнадцатеричным числом. Допускаются только символы 0-9 и a-f (без учёта регистра). Префикс 0x также допускается.

  • message (необязательно): Сообщение об ошибке, которое будет отображаться при сбое валидации. Если опущено, будет использоваться сообщение по умолчанию.

@MinDate(min: Date | (() => Date), message?: string)

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

  • min: Минимально допустимая дата или функция, её возвращающая.
  • message (необязательно): Сообщение об ошибке, которое будет отображаться при сбое валидации. Если опущено, будет использоваться сообщение по умолчанию.

@MaxDate(max: Date | (() => Date), message?: string)

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

  • max: Максимально допустимая дата или функция, её возвращающая.
  • message (необязательно): Сообщение об ошибке, которое будет отображаться при сбое валидации. Если опущено, будет использоваться сообщение по умолчанию.

@With(fieldName: string, message?: string)

Проверяет, что если декорированное поле имеет значение, указанное целевое поле (fieldName) также должно иметь значение, устанавливая обязательную зависимость между двумя полями.

  • fieldName: Имя целевого поля, которое также должно иметь значение, если декорированное поле имеет значение.
  • message (необязательно): Сообщение об ошибке, которое будет отображаться при сбое валидации. Если опущено, будет использоваться сообщение по умолчанию.

@Without(fieldName: string, message?: string)

Проверяет, что если декорированное свойство имеет значение, указанное целевое свойство НЕ ДОЛЖНО иметь значения, устанавливая взаимоисключающее отношение между двумя свойствами.

  • fieldName: Имя целевого свойства, которое должно быть пустым, если декорированное поле имеет значение.
  • message (необязательно): Сообщение об ошибке, которое будет отображаться при сбое валидации. Если опущено, будет использоваться сообщение по умолчанию.

@Each(...args: (Validator | Function)[])

Проверяет каждый отдельный элемент в массиве. Может принимать другие декораторы валидации или пользовательские функции валидации.

  • args: Декоратор валидации (например, @Min(5)) или пользовательская функция (value: any) => boolean.

@ListMaxSize(max: number, message?: string)

Проверяет, что массив содержит не более указанного количества элементов.

  • max: Максимальное количество элементов, допустимое в массиве.
  • message (необязательно): Сообщение об ошибке, отображаемое при неудачной валидации. Если не указано, будет использовано сообщение по умолчанию.

@ListMinSize(min: number, message?: string)

Проверяет, что массив содержит не менее указанного минимального количества элементов.

  • min: Минимальное количество элементов, допустимое в массиве.
  • message (необязательный): Сообщение об ошибке, отображаемое при неудачной валидации. Если не указано, будет использовано сообщение по умолчанию.

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

Вот полный пример того, как использовать декораторы валидации в приложении Express.

import express, { Request, Response, NextFunction } from 'express'
import { bindingCargo, getCargo, Body, Min, Max, Suffix, CargoValidationError } from 'express-cargo'

// 1. Определите класс с правилами источника и валидации
class CreateAssetRequest {
@Body('name')
assetName!: string

@Body('type')
@Suffix('.png')
assetType!: string

@Body('quantity')
@Min(1)
@Max(100)
quantity!: number
}

const app = express()
app.use(express.json())

// 2. Примените промежуточное ПО bindingCargo к маршруту
app.post('/assets', bindingCargo(CreateAssetRequest), (req: Request, res: Response) => {
// 3. Если валидация прошла успешно, получите доступ к данным с помощью getCargo
const assetData = getCargo<CreateAssetRequest>(req)
res.json({
message: 'Ресурс успешно создан!',
data: assetData,
})
})

// 4. Добавьте промежуточное ПО для обработки ошибок, чтобы перехватывать ошибки валидации
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
if (err instanceof CargoValidationError) {
res.status(400).json({
message: 'Ошибка валидации',
errors: err.errors.map(e => e.message),
})
} else {
next(err)
}
})

/*
Чтобы протестировать эту конечную точку, отправьте POST-запрос на /assets.

Пример ВАЛИДНОГО тела запроса:
{
"name": "Мой-Ресурс",
"type": "icon.png",
"quantity": 10
}

Пример НЕВАЛИДНОГО тела запроса:
{
"name": "Мой-Ресурс",
"type": "icon.jpg", // Ошибка @Suffix('.png')
"quantity": 101 // Ошибка @Max(100)
}
*/

Обработка ошибок

Когда валидация не удается, промежуточное ПО bindingCargo выбрасывает CargoValidationError. Вы должны зарегистрировать промежуточное ПО для обработки ошибок Express, чтобы перехватить эту ошибку и отформатировать ответ.

Объект CargoValidationError имеет свойство errors, которое содержит массив экземпляров CargoFieldError. Каждый объект CargoFieldError содержит свойство message с отформатированной строкой, подробно описывающей конкретную ошибку (например, "quantity: quantity must be <= 100").

Как показано в примере кода, обычный способ обработки этого — это перебор массива err.errors для создания простого списка этих сообщений об ошибках.

Пример ответа об ошибке:

Когда отправляется неверное тело запроса из приведенного выше примера, обработчик ошибок выдаст следующий JSON-ответ, который содержит массив отформатированных сообщений об ошибках.

{
"message": "Ошибка валидации",
"errors": [
"type: assetType must end with .png",
"quantity: quantity must be <= 100"
]
}