We use cookies to enhance your experience on the site
CodeWorlds

Advanced Validation Decorators

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.

@IsOptional() — the optional value guard

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}

@IsEnum() — the allowed values guard

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}

@IsArray() and @ArrayMinSize() — the array guards

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.

@IsDateString() — the date guard

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}

@Matches() — the pattern guard (regex)

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}

Full Example — Legion Recruitment Form

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!

Go to CodeWorlds