Ave, strażniku bram! Konsul Caesar.js wie, że bezpieczenstwo imperium zaczyna sie od kontroli tego, co wchodzi przez bramy. Nie mozemy wpuscic do naszego systemu nieprawidlowych danych - to jak wpuszczenie szpiegow do obozu legionow! Czas poznac DTOs i walidacje - tarcze ochronne naszego API.
DTO (Data Transfer Object) to klasa, ktora definiuje ksztalt danych przesylanych do i z naszego API. Pomysl o DTO jak o formularzu rekrutacyjnym do legionu - kazdy nowy legionista musi wypelnic odpowiednie pola, zanim zostanie przyjety.
Bez DTO nasz kontroler przyjmuje cokolwiek - to jak otwarta brama bez strazy:
1// BEZ DTO - niebezpiecznie!
2@Post()
3create(@Body() body: any) {
4 // body moze zawierac cokolwiek... niebezpiecznie!
5 return this.legionariesService.create(body);
6}Z DTO dokladnie definiujemy, jakie dane akceptujemy:
1// Z DTO - bezpieczne jak fort rzymski!
2@Post()
3create(@Body() createLegionaryDto: CreateLegionaryDto) {
4 return this.legionariesService.create(createLegionaryDto);
5}Stworzmy DTO dla naszego systemu legionistow:
1// dto/create-legionary.dto.ts
2export class CreateLegionaryDto {
3 name: string;
4 rank: string;
5 province: string;
6 email: string;
7 experience: number;
8}To jednak tylko ksztalt danych - nie sprawdza jeszcze, czy dane sa prawidlowe. Tu wkracza walidacja!
Aby dodac walidacje, potrzebujemy dwoch bibliotek:
1npm install class-validator class-transformerTeraz dodajmy walidacje do naszego DTO:
1// dto/create-legionary.dto.ts
2import {
3 IsString, IsNumber, IsEmail,
4 MinLength, MaxLength, Min, Max,
5 IsNotEmpty, IsOptional, IsIn
6} from 'class-validator';
7
8export class CreateLegionaryDto {
9 @IsString()
10 @IsNotEmpty()
11 @MinLength(2)
12 @MaxLength(50)
13 name: string;
14
15 @IsString()
16 @IsIn(['Miles', 'Optio', 'Centurio', 'Tribunus', 'Legatus'])
17 rank: string;
18
19 @IsString()
20 @IsNotEmpty()
21 province: string;
22
23 @IsEmail()
24 email: string;
25
26 @IsNumber()
27 @Min(0)
28 @Max(30)
29 experience: number;
30}Oto najczesciej uzywane dekoratory walidacji:
| Dekorator | Opis | |-----------|------| |
@IsString() | Sprawdza czy wartosc to tekst |
| @IsNumber() | Sprawdza czy wartosc to liczba |
| @IsEmail() | Sprawdza czy wartosc to prawidlowy email |
| @IsNotEmpty() | Sprawdza czy pole nie jest puste |
| @MinLength(n) | Minimalna dlugosc tekstu |
| @MaxLength(n) | Maksymalna dlugosc tekstu |
| @Min(n) | Minimalna wartosc liczbowa |
| @Max(n) | Maksymalna wartosc liczbowa |
| @IsOptional() | Pole jest opcjonalne |
| @IsIn([...]) | Wartosc musi byc jedna z podanych |Do czesciowej aktualizacji (PATCH) mozemy uzyc
PartialType, ktory sprawia, ze wszystkie pola sa opcjonalne:1// dto/update-legionary.dto.ts
2import { PartialType } from '@nestjs/mapped-types';
3import { CreateLegionaryDto } from './create-legionary.dto';
4
5export class UpdateLegionaryDto extends PartialType(CreateLegionaryDto) {}
6// Teraz wszystkie pola sa opcjonalne!PartialType automatycznie tworzy nowa klase, w ktorej kazde pole z CreateLegionaryDto staje sie opcjonalne. Dzieki temu nie musimy pisac osobnego DTO z @IsOptional() na kazdym polu.Aby walidacja dzialala, musimy aktywowac
ValidationPipe w naszej aplikacji:1// main.ts
2import { NestFactory } from '@nestjs/core';
3import { ValidationPipe } from '@nestjs/common';
4import { AppModule } from './app.module';
5
6async function bootstrap() {
7 const app = await NestFactory.create(AppModule);
8
9 app.useGlobalPipes(new ValidationPipe({
10 whitelist: true, // Usuwa pola, ktore nie sa w DTO
11 forbidNonWhitelisted: true, // Rzuca blad gdy sa nieznane pola
12 transform: true, // Automatyczna konwersja typow
13 }));
14
15 await app.listen(3000);
16}
17bootstrap();Trzy kluczowe opcje
ValidationPipe:1@Controller('legionaries')
2export class LegionariesController {
3 constructor(private readonly legionariesService: LegionariesService) {}
4
5 @Post()
6 create(@Body() createDto: CreateLegionaryDto) {
7 return this.legionariesService.create(createDto);
8 }
9
10 @Patch(':id')
11 update(
12 @Param('id') id: string,
13 @Body() updateDto: UpdateLegionaryDto,
14 ) {
15 return this.legionariesService.update(Number(id), updateDto);
16 }
17}Kiedy ktos przesle nieprawidlowe dane, ValidationPipe automatycznie zwroci czytelny blad:
1{
2 "statusCode": 400,
3 "message": [
4 "name must be longer than or equal to 2 characters",
5 "email must be an email",
6 "experience must not be greater than 30"
7 ],
8 "error": "Bad Request"
9}DTOs i walidacja to tarcza i miecz naszego imperium - chronia bramy API i zapewniaja, ze do systemu trafiaja tylko prawidlowe dane. Kazdy dobry budowniczy imperium wie, ze silne mury to podstawa!