Kurs NestJS · Moduł 10: Walidacja danych

Zaawansowane dekoratory walidacji

2 min czytania
W tej lekcji6

Podstawowi strażnicy bramy znasz już całkiem nieźle. Teraz czas poznać elitarnych gwardzistów - zaawansowane dekoratory class-validator, które radzą sobie z bardziej skomplikowanymi sytuacjami.

@IsOptional() - strażnik wartości opcjonalnych

Nie każde pole musi być obowiązkowe. Dekorator @IsOptional() mówi: "Jeśli to pole istnieje, sprawdź je. Jeśli nie istnieje - przepuść":

1import { IsOptional, IsString, IsNumber } from 'class-validator';
2
3export class UpdateLegionaryDto {
4  @IsOptional()
5  @IsString()
6  nickname?: string;  // Może nie mieć pseudonimu
7
8  @IsOptional()
9  @IsNumber()
10  bonusPay?: number;  // Dodatkowy żołd jest opcjonalny
11}

@IsEnum() - strażnik dozwolonych wartości

Gdy pole może przyjmować tylko określone wartości, używamy @IsEnum(). To jak lista dozwolonych rang w legionie:

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() i @ArrayMinSize() - strażnicy tablic

Gdy oczekujesz tablicy danych, potrzebujesz specjalnych strażników:

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}

Zwróć uwagę na { each: true } - ten parametr mówi dekoratorowi @IsString(), żeby sprawdził każdy element tablicy, a nie samą tablicę.

@IsDateString() - strażnik dat

Weryfikuje, czy wartość jest poprawnym łańcuchem daty w formacie ISO 8601:

1import { IsDateString } from 'class-validator';
2
3export class CreateEventDto {
4  @IsDateString()
5  enlistmentDate: string;
6  // "2024-03-15T10:00:00Z", "wczoraj"
7}

@Matches() - strażnik wzorców (regex)

Najuniwersalniejszy strażnik - sprawdza, czy wartość pasuje do wyrażenia regularnego:

1import { Matches, IsString } from 'class-validator';
2
3export class CreateLegionaryDto {
4  @IsString()
5  @Matches(/^LEG-[A-Z]{3}-\d{4}$/, {
6    message: 'Numer identyfikacyjny musi mieć format LEG-XXX-0000',
7  })
8  militaryId: string;
9  // "LEG-ROM-0042", "123ABC"
10}

Pełny przykład - formularz rekrutacji do legionu

Połączmy wszystkie zaawansowane dekoratory w kompletnym 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}

Mając te dekoratory w swoim arsenale, możesz walidować praktycznie dowolne dane. Strażnicy bramy twojego API są teraz dobrze wyszkoleni!

Kod do tej lekcji: src/advanced-decorators.ts
1// Zaawansowane dekoratory walidacji
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// Enumy rang legionistów
16enum LegionaryRank {
17  MILES = 'miles',
18  OPTIO = 'optio',
19  CENTURIO = 'centurio',
20  LEGATUS = 'legatus',
21}
22
23// TODO: Uzupełnij DTO zaawansowanymi dekoratorami
24export class RecruitLegionaryDto {
25  @IsString()
26  @IsNotEmpty()
27  name: string;
28
29  // TODO: Dodaj @IsEnum z LegionaryRank
30  rank: LegionaryRank;
31
32  @IsNumber()
33  @Min(16)
34  age: number;
35
36  // TODO: Dodaj @IsDateString()
37  enlistmentDate: string;
38
39  // TODO: Dodaj @Matches z regexem /^LEG-[A-Z]{3}-\d{4}$/
40  militaryId: string;
41
42  // TODO: Dodaj @IsArray, @ArrayMinSize(1), @IsString({ each: true })
43  skills: string[];
44
45  // TODO: Dodaj @IsOptional() i @IsString()
46  nickname?: string;
47}
48
49console.log('Zaawansowane dekoratory gotowe!');
50

Widzisz błąd w tej lekcji?

Sprawdź się

Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.

  1. 1. Co robi dekorator @IsOptional() w class-validator?

  2. 2. Do czego służy dekorator @IsEnum() w class-validator?

To 2 z 3 pytań do tej lekcji. Pozostałe rozwiążesz w grze.

Zadania praktyczne w grze

  • Edytor kodu

    Uzupełnij enum ProvinceType i dodaj dekoratory walidacji do CreateProvinceDto

  • Układanie w pionie

    Uporządkuj dekoratory od najmniej do najbardziej restrykcyjnego:

  • Edytor kodu

    Uzupełnij dekoratory @Matches i @IsDateString w CreateDocumentDto

  • Klikanie w kolejności

    Ułóż elementy dekoratora @Matches w prawidłowej kolejności:

Przydatne artykuły