Kurs NestJS · Moduł 11: Swagger i OpenAPI

Dokumentacja DTO - pieczęcie na pergaminie

3 min czytania
W tej lekcji7

Każdy dokument w cesarskiej kancelarii musiał mieć precyzyjnie opisane pola - imię petenta, rodzaj sprawy, datę i pieczęć. W NestJS odpowiednikiem tych dokumentów są DTO (Data Transfer Objects), a dekorator @ApiProperty() opisuje każde pole tak, aby Swagger UI mógł je wyświetlić.

@ApiProperty - Podstawy

Dekorator @ApiProperty() opisuje pojedyncze pole w klasie DTO:

1import { ApiProperty } from '@nestjs/swagger';
2
3export class CreateLegionaryDto {
4  @ApiProperty({
5    description: 'Imię legionisty',
6    example: 'Marcus Aurelius',
7  })
8  name: string;
9
10  @ApiProperty({
11    description: 'Ranga w legionie',
12    example: 'Centurio',
13  })
14  rank: string;
15
16  @ApiProperty({
17    description: 'Lata doświadczenia',
18    example: 5,
19    minimum: 0,
20    maximum: 40,
21  })
22  experience: number;
23}

Opcje @ApiProperty

Dekorator przyjmuje wiele opcji konfiguracyjnych:

OpcjaOpisPrzykład
descriptionOpis pola'Imię legionisty'
examplePrzykładowa wartość'Marcus'
requiredCzy pole jest wymaganetrue / false
defaultWartość domyślna'Miles'
enumLista dozwolonych wartości['Centurio', 'Miles']
typeTyp polaString, Number, Boolean
isArrayCzy pole jest tablicątrue
minimumMinimalna wartość (number)0
maximumMaksymalna wartość (number)100
minLengthMinimalna długość (string)2
maxLengthMaksymalna długość (string)50

Pola opcjonalne z @ApiPropertyOptional

Dla pól opcjonalnych używamy @ApiPropertyOptional():

1import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
2
3export class UpdateLegionaryDto {
4  @ApiPropertyOptional({
5    description: 'Nowa ranga legionisty',
6    example: 'Optio',
7  })
8  rank?: string;
9
10  @ApiPropertyOptional({
11    description: 'Nowy legion przypisania',
12    example: 'Legio III Augusta',
13  })
14  legio?: string;
15
16  @ApiPropertyOptional({
17    description: 'Dodatkowe doświadczenie',
18    example: 2,
19    minimum: 0,
20  })
21  additionalExperience?: number;
22}

Pola z enum - rangi legionowe

Enum jest szczególnie przydatny do pól z ograniczonym zestawem wartości:

1export enum LegionaryRank {
2  MILES = 'Miles',
3  OPTIO = 'Optio',
4  CENTURIO = 'Centurio',
5  TRIBUNUS = 'Tribunus',
6  LEGATUS = 'Legatus',
7}
8
9export class CreateLegionaryDto {
10  @ApiProperty({
11    description: 'Ranga legionisty',
12    enum: LegionaryRank,
13    example: LegionaryRank.MILES,
14  })
15  rank: LegionaryRank;
16}

Zagnieżdżone obiekty - struktura legionu

Dla zagnieżdżonych DTO używamy opcji type:

1export class AddressDto {
2  @ApiProperty({ description: 'Nazwa prowincji', example: 'Pannonia' })
3  province: string;
4
5  @ApiProperty({ description: 'Nazwa miasta', example: 'Aquincum' })
6  city: string;
7}
8
9export class LegionDto {
10  @ApiProperty({ description: 'Nazwa legionu', example: 'Legio X Gemina' })
11  name: string;
12
13  @ApiProperty({
14    description: 'Lokalizacja legionu',
15    type: AddressDto,
16  })
17  location: AddressDto;
18
19  @ApiProperty({
20    description: 'Lista centurionów',
21    type: [String],
22    example: ['Marcus', 'Julius', 'Gaius'],
23  })
24  centurions: string[];
25}

DTO odpowiedzi

Warto tworzyć osobne DTO dla odpowiedzi API:

1export class LegionaryResponseDto {
2  @ApiProperty({ description: 'ID legionisty', example: '507f1f77bcf86cd799439011' })
3  id: string;
4
5  @ApiProperty({ description: 'Imię legionisty', example: 'Marcus Aurelius' })
6  name: string;
7
8  @ApiProperty({ description: 'Ranga', enum: LegionaryRank })
9  rank: LegionaryRank;
10
11  @ApiProperty({ description: 'Data rekrutacji', example: '2024-01-15T10:30:00Z' })
12  recruitedAt: Date;
13
14  @ApiProperty({ description: 'Czy aktywny', example: true })
15  isActive: boolean;
16}

Ćwiczenie praktyczne

Stwórz dokumentację DTO dla systemu zarządzania prowincjami Imperium:

Kod do tej lekcji: src/province.dto.ts
1// Dokumentacja DTO - pieczecie na pergaminie
2import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
3
4// TODO: Stworz enum ProvinceStatus z wartosciami:
5// ACTIVE = 'Active', CONQUERED = 'Conquered', REBELLING = 'Rebelling'
6export enum ProvinceStatus {
7  // TODO: Uzupelnij wartosci enum
8}
9
10export class CreateProvinceDto {
11  // TODO: Dodaj @ApiProperty z description i example
12  name: string;
13
14  // TODO: Dodaj @ApiProperty z description i example
15  governor: string;
16
17  // TODO: Dodaj @ApiProperty z enum ProvinceStatus
18  status: ProvinceStatus;
19
20  // TODO: Dodaj @ApiPropertyOptional z description, example, minimum
21  population?: number;
22
23  // TODO: Dodaj @ApiProperty z description i type [String]
24  legions: string[];
25}
26
27export class ProvinceResponseDto {
28  @ApiProperty({ description: 'ID prowincji', example: '64a1b2c3d4e5f6a7b8c9d0e1' })
29  id: string;
30
31  @ApiProperty({ description: 'Nazwa prowincji', example: 'Pannonia' })
32  name: string;
33
34  @ApiProperty({ description: 'Namiestnik', example: 'Lucius Verus' })
35  governor: string;
36
37  @ApiProperty({ description: 'Status prowincji', enum: ProvinceStatus })
38  status: ProvinceStatus;
39
40  @ApiPropertyOptional({ description: 'Populacja', example: 500000 })
41  population?: number;
42
43  @ApiProperty({ description: 'Data aneksji' })
44  annexedAt: Date;
45}
46
47console.log("@ApiProperty - wymagane pola");
48console.log("@ApiPropertyOptional - opcjonalne pola");
49console.log("Opcje: description, example, enum, type");
50console.log("minimum, maximum, minLength, maxLength");
51

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 @ApiProperty() na polu klasy DTO?

  2. 2. Jaki dekorator służy do oznaczania pól opcjonalnych w DTO dla Swagger?

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

Zadania praktyczne w grze

  • Edytor kodu

    Uzupełnij CreateCenturioDto dodając @ApiProperty z description i example do każdego pola

  • Układanie w pionie

    Ułóż elementy @ApiProperty z enum w prawidłowej kolejności:

  • Klikanie w kolejności

    Ułóż opcje @ApiProperty od opisu do walidacji wartości:

  • Edytor kodu

    Uzupełnij CreateProvinceDto z enum ProvinceType, zagnieżdżonym LocationDto i tablicą stringów

Przydatne artykuły