Валидация на основе существующих схем в Class-validator строится вокруг идеи повторного использования описаний правил, заданных через декораторы, а также композиции классов-DTO. Подход позволяет минимизировать дублирование, стандартизировать проверку данных и выстраивать единый слой валидации для различных сценариев приложения.
В основе механизма лежит модель, в которой класс рассматривается как контракт данных, а декораторы — как декларативное описание ограничений для каждого поля.
Основной способ повторного применения схем заключается в использовании классов как строительных блоков.
import { IsString, IsInt, Min } from 'class-validator';
export class UserBase {
@IsString()
username: string;
@IsInt()
@Min(0)
age: number;
}
Этот класс становится базовой схемой, которую можно включать в другие структуры данных без дублирования правил.
Наследование позволяет расширять существующую модель, сохраняя исходные правила валидации.
export class CreateUserDto extends UserBase {
@IsString()
password: string;
}
В данном случае правила валидации объединяются: поля
username и age сохраняют ограничения, а
password добавляется как новое требование.
Такой подход формирует иерархию схем, где базовый класс выступает фундаментом для более специализированных DTO.
При работе со сложными структурами данных используется вложенная валидация. Она позволяет включать одну схему внутрь другой без потери типизации и правил.
import { ValidateNested, IsString } from 'class-validator';
import { Type } from 'class-transformer';
export class Profile {
@IsString()
bio: string;
}
export class User {
@IsString()
username: string;
@ValidateNested()
@Type(() => Profile)
profile: Profile;
}
В данном случае схема Profile является переиспользуемым
элементом, встроенным в структуру User.
Механизм @ValidateNested() активирует рекурсивную
проверку вложенного объекта, а @Type() обеспечивает
корректную трансформацию данных перед валидацией.
В сложных системах часто требуется использовать не всю схему целиком, а только её часть. Для этого применяется комбинация базовых классов и вспомогательных DTO.
export class Address {
@IsString()
city: string;
@IsString()
street: string;
}
export class UserWithAddress {
@IsString()
username: string;
@ValidateNested()
@Type(() => Address)
address: Address;
}
Схема Address может использоваться в различных
контекстах: доставка, профиль пользователя, биллинг. Это снижает
вероятность рассинхронизации правил между модулями системы.
При необходимости объединения нескольких схем в одну структуру используется композиция на уровне полей.
export class Credentials {
@IsString()
login: string;
@IsString()
password: string;
}
export class UserProfile {
@IsString()
name: string;
}
export class AuthenticatedUser {
@ValidateNested()
@Type(() => Credentials)
credentials: Credentials;
@ValidateNested()
@Type(() => UserProfile)
profile: UserProfile;
}
Такая модель отражает принцип сборки сложных контрактов из независимых блоков. Каждый блок сохраняет собственную ответственность и может быть переиспользован в других структурах.
Механизм частичных схем часто реализуется через создание классов-потомков с ослабленными ограничениями.
import { IsOptional, IsString } from 'class-validator';
export class UpdateUserDto {
@IsOptional()
@IsString()
username?: string;
@IsOptional()
@IsString()
bio?: string;
}
В этом случае исходные правила трансформируются в вариативную форму. Поля сохраняют типизацию и валидируемость, но становятся необязательными, что характерно для операций обновления данных.
Абстрактные классы позволяют формировать стандартизированные контракты, которые не предназначены для прямого использования, но задают общие правила.
export abstract class TimestampedEntity {
@IsDate()
createdAt: Date;
@IsDate()
updatedAt: Date;
}
Дальнейшие схемы наследуют поведение:
export class Post extends TimestampedEntity {
@IsString()
title: string;
}
Такой подход фиксирует повторяющиеся поля в одном месте и обеспечивает консистентность данных во всех сущностях.
Переиспользование схем также реализуется через дополнительное наложение декораторов на уже существующие классы.
export class BaseProduct {
@IsString()
name: string;
}
export class Product extends BaseProduct {
@IsInt()
price: number;
}
Декораторы не модифицируют исходную схему, а расширяют её, формируя итоговый набор правил валидации при построении экземпляра класса.
Валидация может быть организована рекурсивно, когда одна и та же схема используется на нескольких уровнях структуры данных.
export class Category {
@IsString()
name: string;
@ValidateNested({ each: true })
@Type(() => Category)
children: Category[];
}
Такая конструкция демонстрирует повторное применение одной схемы внутри самой себя, что характерно для древовидных структур данных.
Переиспользуемые схемы в Class-validator формируют слой доменной модели, в котором каждая сущность описывает устойчивый набор правил. Эти правила сохраняются независимо от контекста использования: создание, обновление, передача между сервисами или сериализация.
Стабильность достигается за счёт строгой декларативности декораторов и их привязки к классу, а не к конкретной операции.
Разделение схем на независимые блоки позволяет формировать библиотеки DTO, пригодные для использования в различных частях приложения. Такой подход снижает связанность модулей и делает правила валидации предсказуемыми при масштабировании системы.
Комбинация наследования, композиции и вложенной валидации формирует единый механизм построения сложных контрактов на основе уже определённых схем без необходимости их повторного описания.