You already know the basic gate guards quite well. Now it's time to meet the elite guardsmen — advanced class-validator decorators that handle more complex situations.
Not every field needs to be required. The
@IsOptional() decorator says: "If this field exists, check it. If it doesn't exist — let it pass":1import { IsOptional, IsString, IsNumber } from 'class-validator';
2
3export class UpdateLegionaryDto {
4 @IsOptional()
5 @IsString()
6 nickname?: string; // May not have a nickname
7
8 @IsOptional()
9 @IsNumber()
10 bonusPay?: number; // Bonus pay is optional
11}When a field can only accept specific values, we use
@IsEnum(). It's like a list of allowed ranks in the legion:1import { IsEnum } from 'class-validator';
2
3enum LegionaryRank {
4 MILES = 'miles',
5 OPTIO = 'optio',
6 CENTURIO = 'centurio',
7 LEGATUS = 'legatus',
8}
9
10export class CreateLegionaryDto {
11 @IsEnum(LegionaryRank)
12 rank: LegionaryRank;
13 // 'centurio' ✅, 'imperator' ❌
14}When you expect an array of data, you need special guards:
1import { IsArray, ArrayMinSize, IsString } from 'class-validator';
2
3export class CreateLegioDto {
4 @IsArray()
5 @ArrayMinSize(1)
6 @IsString({ each: true })
7 skills: string[];
8 // ["combat", "march"] ✅, [] ❌, "combat" ❌
9}Note the
{ each: true } — this parameter tells the @IsString() decorator to check each element of the array, not the array itself.Verifies whether the value is a valid date string in ISO 8601 format:
1import { IsDateString } from 'class-validator';
2
3export class CreateEventDto {
4 @IsDateString()
5 enlistmentDate: string;
6 // "2024-03-15T10:00:00Z" ✅, "yesterday" ❌
7}The most universal guard — checks whether the value matches a regular expression:
1import { Matches, IsString } from 'class-validator';
2
3export class CreateLegionaryDto {
4 @IsString()
5 @Matches(/^LEG-[A-Z]{3}-\d{4}$/, {
6 message: 'Military ID must have the format LEG-XXX-0000',
7 })
8 militaryId: string;
9 // "LEG-ROM-0042" ✅, "123ABC" ❌
10}Let's combine all the advanced decorators in a complete DTO:
1import {
2 IsString,
3 IsNotEmpty,
4 IsEnum,
5 IsOptional,
6 IsArray,
7 ArrayMinSize,
8 IsDateString,
9 Matches,
10 IsNumber,
11 Min,
12 Max,
13 MinLength,
14} from 'class-validator';
15
16enum LegionaryRank {
17 MILES = 'miles',
18 OPTIO = 'optio',
19 CENTURIO = 'centurio',
20 LEGATUS = 'legatus',
21}
22
23export class RecruitLegionaryDto {
24 @IsString()
25 @IsNotEmpty()
26 @MinLength(2)
27 name: string;
28
29 @IsEnum(LegionaryRank)
30 rank: LegionaryRank;
31
32 @IsNumber()
33 @Min(16)
34 @Max(65)
35 age: number;
36
37 @IsDateString()
38 enlistmentDate: string;
39
40 @Matches(/^LEG-[A-Z]{3}-\d{4}$/)
41 militaryId: string;
42
43 @IsArray()
44 @ArrayMinSize(1)
45 @IsString({ each: true })
46 skills: string[];
47
48 @IsOptional()
49 @IsString()
50 nickname?: string;
51}With these decorators in your arsenal, you can validate virtually any data. Your API's gate guards are now well trained!