NestJS course Β· Module 10: Data Validation
Advanced Validation Decorators
In this lesson6
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!
Code for this lesson: src/advanced-decorators.ts
1// Advanced validation decorators
2import {
3 IsString,
4 IsNotEmpty,
5 IsEnum,
6 IsOptional,
7 IsArray,
8 ArrayMinSize,
9 IsDateString,
10 Matches,
11 IsNumber,
12 Min,
13} from 'class-validator';
14
15// Legionary rank enums
16enum LegionaryRank {
17 MILES = 'miles',
18 OPTIO = 'optio',
19 CENTURIO = 'centurio',
20 LEGATUS = 'legatus',
21}
22
23// TODO: Complete the DTO with advanced decorators
24export class RecruitLegionaryDto {
25 @IsString()
26 @IsNotEmpty()
27 name: string;
28
29 // TODO: Add @IsEnum with LegionaryRank
30 rank: LegionaryRank;
31
32 @IsNumber()
33 @Min(16)
34 age: number;
35
36 // TODO: Add @IsDateString()
37 enlistmentDate: string;
38
39 // TODO: Add @Matches with regex /^LEG-[A-Z]{3}-\d{4}$/
40 militaryId: string;
41
42 // TODO: Add @IsArray, @ArrayMinSize(1), @IsString({ each: true })
43 skills: string[];
44
45 // TODO: Add @IsOptional() and @IsString()
46 nickname?: string;
47}
48
49console.log('Advanced decorators ready!');
50Spotted a mistake in this lesson?
Check yourself
Answer the questions from this lesson. Pick an answer to see right away whether it is correct.
1. What does the @IsOptional() decorator in class-validator do?
2. What is the @IsEnum() decorator used for in class-validator?
These are 2 of 3 questions for this lesson. Solve the rest in the game.
Hands-on tasks in the game
- Code editor
Complete the ProvinceType enum and add validation decorators to CreateProvinceDto
- Vertical ordering
Arrange the decorators from least to most restrictive:
- Code editor
Complete the @Matches and @IsDateString decorators in CreateDocumentDto
- Click in order
Arrange the elements of the @Matches decorator in the correct order: