Первый пример валидации

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

Ключевые элементы первого примера:

  • класс как контейнер данных;
  • декораторы валидации;
  • функция validate для запуска проверки.

Установка зависимостей

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

npm install class-validator class-transformer

Также требуется включить поддержку декораторов в TypeScript:

{
  "experimentalDecorators": true,
  "emitDecoratorMetadata": true
}

Если используется чистый JavaScript с Babel, необходимо подключить соответствующий плагин:

npm install --save-dev @babel/plugin-proposal-decorators

Первый минимальный пример

Валидация начинается с описания класса, который представляет структуру входных данных.

import { validate } from "class-validator";
import { IsString, Length, IsInt, Min, Max } from "class-validator";

class User {
  @IsString()
  name: string;

  @IsInt()
  @Min(18)
  @Max(60)
  age: number;
}

В данном случае задаются два поля:

  • name должен быть строкой;
  • age должен быть целым числом в диапазоне от 18 до 60.

Создание объекта и запуск проверки

После описания модели создаётся экземпляр класса и выполняется валидация.

const user = new User();
user.name = "Иван";
user.age = 17;

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

Если данные не соответствуют правилам, возвращается массив ошибок.


Структура объекта ошибок

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

Пример упрощённой структуры:

[
  {
    property: "age",
    constraints: {
      min: "age must not be less than 18"
    }
  }
]

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

  • property — имя поля, где обнаружена ошибка;
  • constraints — набор нарушенных правил;
  • children — вложенные ошибки (для вложенных объектов).

Пример корректных данных

const user = new User();
user.name = "Иван";
user.age = 25;

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

Пустой массив означает успешное прохождение всех проверок.


Валидация с использованием нескольких правил

Одно поле может содержать несколько ограничений одновременно.

class Product {
  @IsString()
  @Length(3, 20)
  title: string;

  @IsInt()
  @Min(1)
  price: number;
}

Здесь:

  • title должен быть строкой длиной от 3 до 20 символов;
  • price должен быть целым числом не меньше 1.

Синхронный стиль обработки результата

Хотя validate возвращает Promise, результат удобно обрабатывать через async/await.

async function run() {
  const product = new Product();
  product.title = "TV";
  product.price = 0;

  const errors = await validate(product);

  if (errors.length > 0) {
    console.log("Ошибки валидации:", errors);
  }
}

Поведение при пустых значениях

По умолчанию многие декораторы не пропускают undefined и null, если не указано обратное.

Пример:

class Profile {
  @IsString()
  nickname: string;
}

Если nickname не задан, будет ошибка валидации.

Для разрешения пустых значений используется:

import { IsOptional, IsString } from "class-validator";

class Profile {
  @IsOptional()
  @IsString()
  nickname?: string;
}

Преобразование входных данных

В реальных приложениях данные часто приходят в виде обычных объектов JSON. Для корректной работы class-validator требуется преобразование в экземпляр класса.

import { plainToInstance } from "class-transformer";

const raw = {
  name: "Иван",
  age: "20"
};

const user = plainToInstance(User, raw);

После этого объект можно безопасно валидировать:

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

Типичная ошибка первого использования

Распространённая проблема заключается в попытке валидировать обычный объект без преобразования в класс:

const user = {
  name: "Иван",
  age: 20
};

validate(user); // некорректное использование

Декораторы работают только с экземплярами классов, поэтому требуется создание объекта через new или plainToInstance.


Минимальный рабочий шаблон

import "reflect-metadata";
import { validate, IsString, IsInt } from "class-validator";

class User {
  @IsString()
  name: string;

  @IsInt()
  age: number;
}

async function bootstrap() {
  const user = new User();
  user.name = "Иван";
  user.age = 30;

  const errors = await validate(user);

  console.log(errors);
}

bootstrap();