Введение в class-validator
class-validator — это мощная и популярная библиотека для валидации данных в TypeScript и JavaScript, построенная на основе декораторов. Она позволяет декларативно описывать правила валидации прямо внутри классов, используя аннотации. Это делает код чистым, читаемым и легко поддерживаемым.
Библиотека особенно полезна при разработке серверных приложений (например, на NestJS или Express), где необходимо проверять входящие запросы, данные из форм, конфигурации и любые другие структуры данных. Вместо того чтобы писать громоздкие цепочки if-else, вы просто добавляете декораторы к свойствам класса.
Зачем нужна class-validator?
- Декларативность: Правила валидации определяются рядом с данными, что улучшает читаемость.
- Мощный набор валидаторов: Включает десятки встроенных декораторов для проверки строк, чисел, дат, массивов, вложенных объектов и многого другого.
- Кастомные валидаторы: Позволяет легко создавать свои собственные правила.
- Интеграция с TypeScript: Полная поддержка типов и декораторов.
- Асинхронная валидация: Поддерживает проверки, требующие асинхронных операций (например, проверка уникальности в БД).
Установка
Для использования class-validator вам потребуется Node.js и npm/yarn. Установите библиотеку и необходимые зависимости:
npm install class-validator class-transformer reflect-metadata
Или через yarn:
yarn add class-validator class-transformer reflect-metadata
Важно: Библиотека reflect-metadata обязательна для работы декораторов. Убедитесь, что она импортирована в вашем главном файле (например, index.ts или main.ts):
import 'reflect-metadata';
Также убедитесь, что в вашем tsconfig.json включены следующие настройки:
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
Быстрый старт
Давайте создадим простую модель пользователя и провалидируем её.
import 'reflect-metadata';
import { validate, IsString, IsEmail, MinLength } from 'class-validator';
import { plainToClass } from 'class-transformer';
class User {
@IsString()
@MinLength(3, { message: 'Имя должно содержать минимум 3 символа' })
name: string;
@IsEmail({}, { message: 'Некорректный email' })
email: string;
constructor(name: string, email: string) {
this.name = name;
this.email = email;
}
}
async function main() {
// Создаем объект с некорректными данными
const userData = { name: 'Jo', email: 'not-an-email' };
// Преобразуем простой объект в экземпляр класса
const user = plainToClass(User, userData);
// Валидируем
const errors = await validate(user);
if (errors.length > 0) {
console.log('Ошибки валидации:', errors);
errors.forEach(error => {
console.log(`Поле: ${error.property}`);
for (const constraint in error.constraints) {
console.log(` - ${error.constraints[constraint]}`);
}
});
} else {
console.log('Валидация пройдена успешно!');
}
}
main();
// Вывод:
// Ошибки валидации: [...]
// Поле: name
// - Имя должно содержать минимум 3 символа
// Поле: email
// - Некорректный email
Основные методы и декораторы
1. @IsString()
Что делает: Проверяет, является ли значение строкой.
Параметры: Принимает опциональный объект с опциями валидации (например, { message: '...' }).
class Product {
@IsString()
title: string;
}
2. @IsNumber()
Что делает: Проверяет, является ли значение числом (включая числа с плавающей точкой).
Параметры: Принимает опции, включая allowNaN (допускать NaN) и allowInfinity.
class Order {
@IsNumber({ allowNaN: false })
price: number;
}
3. @IsEmail()
Что делает: Проверяет, является ли строка корректным email-адресом.
Параметры: Принимает опции для настройки проверки (например, allow_display_name).
class Contact {
@IsEmail()
email: string;
}
4. @MinLength() и @MaxLength()
Что делает: Проверяют минимальную и максимальную длину строки.
Параметры: Число — требуемая длина.
class Post {
@MinLength(10, { message: 'Заголовок слишком короткий' })
@MaxLength(100, { message: 'Заголовок слишком длинный' })
title: string;
}
5. @Min() и @Max()
Что делает: Проверяют минимальное и максимальное числовое значение.
Параметры: Число — пороговое значение.
class Product {
@Min(0)
@Max(10000)
price: number;
}
6. @IsArray()
Что делает: Проверяет, является ли значение массивом.
Параметры: Опциональные опции.
class Article {
@IsArray()
tags: string[];
}
7. @ArrayMinSize() и @ArrayMaxSize()
Что делает: Проверяют минимальный и максимальный размер массива.
Параметры: Число — требуемый размер.
class Team {
@ArrayMinSize(2, { message: 'В команде должно быть минимум 2 участника' })
@ArrayMaxSize(10)
members: string[];
}
8. @IsBoolean()
Что делает: Проверяет, является ли значение булевым (true/false).
Параметры: Опциональные опции.
class Settings {
@IsBoolean()
isActive: boolean;
}
9. @IsOptional()
Что делает: Указывает, что свойство может быть пропущено (undefined) и не будет валидироваться, если его нет.
Параметры: Нет.
class Profile {
@IsString()
username: string;
@IsOptional()
@IsString()
bio?: string;
}
10. @ValidateNested()
Что делает: Позволяет валидировать вложенные объекты. Обязательно использовать с @Type() из class-transformer.
Параметры: Опциональные опции.
import { Type } from 'class-transformer';
class Address {
@IsString()
street: string;
@IsString()
city: string;
}
class Person {
@ValidateNested()
@Type(() => Address)
address: Address;
}
11. @IsEnum()
Что делает: Проверяет, является ли значение одним из значений перечисления (enum).
Параметры: Объект enum.
enum Role {
ADMIN = 'admin',
USER = 'user',
GUEST = 'guest'
}
class User {
@IsEnum(Role)
role: Role;
}
12. @Matches()
Что делает: Проверяет, соответствует ли строка регулярному выражению.
Параметры: RegExp или строка с регулярным выражением.
class Code {
@Matches(/^[A-Z]{3}-\d{4}$/, { message: 'Код должен быть формата ABC-1234' })
productCode: string;
}
Реальный практический пример
Рассмотрим пример создания REST API для регистрации пользователя с использованием Express и class-validator.
import 'reflect-metadata';
import express, { Request, Response } from 'express';
import { validate, IsString, IsEmail, MinLength, IsOptional, IsDateString } from 'class-validator';
import { plainToClass } from 'class-transformer';
class CreateUserDto {
@IsString()
@MinLength(3)
username: string;
@IsEmail()
email: string;
@IsString()
@MinLength(8, { message: 'Пароль должен быть минимум 8 символов' })
password: string;
@IsOptional()
@IsDateString()
birthDate?: string;
}
const app = express();
app.use(express.json());
app.post('/users', async (req: Request, res: Response) => {
const userDto = plainToClass(CreateUserDto, req.body);
const errors = await validate(userDto);
if (errors.length > 0) {
const formattedErrors = errors.map(error => ({
field: error.property,
messages: Object.values(error.constraints || {})
}));
return res.status(400).json({ errors: formattedErrors });
}
// Здесь можно сохранить пользователя в БД
res.status(201).json({ message: 'Пользователь создан', data: userDto });
});
app.listen(3000, () => console.log('Server running on port 3000'));
Советы и типичные ошибки
Советы
- Используйте class-transformer: Всегда преобразуйте обычные объекты в экземпляры классов с помощью
plainToClassперед валидацией. Иначе декораторы не сработают. - Кастомизируйте сообщения об ошибках: Используйте параметр
{ message: 'Ваше сообщение' }для каждого декоратора, чтобы сделать ошибки понятными для пользователя. - Группируйте валидации: Используйте группы (
groups) для разных сценариев (создание, обновление). - Создавайте кастомные валидаторы: Если встроенных недостаточно, используйте
@ValidatorConstraint().
Типичные ошибки
- Забыли импортировать reflect-metadata: Без этого декораторы не будут работать.
- Не включили experimentalDecorators в tsconfig: TypeScript не поймет синтаксис декораторов.
- Валидация без преобразования: Если вы передаете простой объект напрямую в
validate(), валидация не сработает, так как декораторы не привязаны к свойствам объекта. - Игнорирование асинхронности:
validate()возвращает Promise, не забывайте использоватьawait.
Ссылки и ресурсы
- Официальный репозиторий: github.com/typestack/class-validator
- Документация: README на GitHub
- NPM:
Также в библиотеке
Генерация PDF-отчётов на C++ с libharu и PoDoFo
image для Rust: полное руководство с примерами
Redis клиент для Swift (iOS/macOS) – RediStack
Тестирование в JavaScript (Node.js): фреймворки и инструменты
Работа с XML в C# (.NET): Полное руководство
Рекомендаций