Używamy cookies, żeby zwiększyć Twoje doświadczenia na stronie
CodeWorlds

Projekt główny — Kompletny system walidacji Imperium

Nadszedł czas na prawdziwą próbę, legioniście! W tym projekcie połączysz wszystkie techniki walidacji poznane w tym module, aby zbudować kompletny system ochrony bram dla Imperium Romanum.

Zadanie

Zbudujesz system zarządzania legionami z pełną walidacją danych wejściowych. System składa się z DTO do tworzenia legionu, legionistów i broni, z custom validatorami i transformacjami.

Krok 1 — Enumy i typy bazowe

1// enums.ts
2export enum LegionaryRank {
3  MILES = 'miles',
4  OPTIO = 'optio',
5  CENTURIO = 'centurio',
6  TRIBUNUS = 'tribunus',
7  LEGATUS = 'legatus',
8}
9
10export enum WeaponType {
11  GLADIUS = 'gladius',
12  PILUM = 'pilum',
13  SCUTUM = 'scutum',
14  PUGIO = 'pugio',
15}
16
17export enum LegionStatus {
18  ACTIVE = 'active',
19  RESERVES = 'reserves',
20  DISBANDED = 'disbanded',
21}

Krok 2 — DTO broni z walidacją

1// weapon.dto.ts
2import { IsString, IsNotEmpty, IsEnum, IsNumber, Min, Max } from 'class-validator';
3
4export class CreateWeaponDto {
5  @IsString()
6  @IsNotEmpty()
7  name: string;
8
9  @IsEnum(WeaponType)
10  type: WeaponType;
11
12  @IsNumber()
13  @Min(1)
14  @Max(100)
15  damage: number;
16
17  @IsNumber()
18  @Min(0)
19  @Max(10)
20  weight: number;
21}

Krok 3 — DTO legionisty z zagnieżdżoną walidacją

1// legionary.dto.ts
2import {
3  IsString, IsNotEmpty, IsEnum, IsNumber,
4  Min, Max, MinLength, MaxLength, IsArray,
5  ArrayMinSize, ValidateNested, IsOptional, Matches,
6} from 'class-validator';
7import { Type, Transform, Exclude } from 'class-transformer';
8
9export class CreateLegionaryDto {
10  @IsString()
11  @IsNotEmpty()
12  @MinLength(2)
13  @MaxLength(50)
14  @Transform(({ value }) => value.trim())
15  name: string;
16
17  @IsEnum(LegionaryRank)
18  rank: LegionaryRank;
19
20  @IsNumber()
21  @Min(16)
22  @Max(65)
23  age: number;
24
25  @Matches(/^LEG-[A-Z]{2,4}-\d{4}$/, {
26    message: 'ID musi mieć format LEG-XX-0000',
27  })
28  militaryId: string;
29
30  @IsArray()
31  @ArrayMinSize(1)
32  @IsString({ each: true })
33  skills: string[];
34
35  @ValidateNested()
36  @Type(() => CreateWeaponDto)
37  primaryWeapon: CreateWeaponDto;
38
39  @IsOptional()
40  @ValidateNested()
41  @Type(() => CreateWeaponDto)
42  secondaryWeapon?: CreateWeaponDto;
43}

Krok 4 — DTO legionu z tablicą zagnieżdżonych obiektów

1// legion.dto.ts
2export class CreateLegionDto {
3  @IsString()
4  @IsNotEmpty()
5  @MinLength(3)
6  name: string;
7
8  @IsEnum(LegionStatus)
9  status: LegionStatus;
10
11  @IsNumber()
12  @Min(1000)
13  @Max(6000)
14  maxSoldiers: number;
15
16  @ValidateNested({ each: true })
17  @Type(() => CreateLegionaryDto)
18  @IsArray()
19  @ArrayMinSize(1)
20  soldiers: CreateLegionaryDto[];
21}

Krok 5 — Custom validator

1// validators/is-valid-military-id.ts
2import {
3  ValidatorConstraint,
4  ValidatorConstraintInterface,
5  registerDecorator,
6  ValidationOptions,
7} from 'class-validator';
8
9@ValidatorConstraint({ async: false })
10class IsValidMilitaryIdConstraint implements ValidatorConstraintInterface {
11  validate(value: string): boolean {
12    if (!value) return false;
13    const parts = value.split('-');
14    if (parts.length !== 3) return false;
15    if (parts[0] !== 'LEG') return false;
16    const numericPart = parseInt(parts[2], 10);
17    return numericPart > 0 && numericPart <= 9999;
18  }
19
20  defaultMessage(): string {
21    return 'Niepoprawny identyfikator wojskowy';
22  }
23}
24
25export function IsValidMilitaryId(options?: ValidationOptions) {
26  return function (object: object, propertyName: string) {
27    registerDecorator({
28      target: object.constructor,
29      propertyName,
30      options,
31      validator: IsValidMilitaryIdConstraint,
32    });
33  };
34}

Krok 6 — Response DTO z transformacjami

1// legionary-response.dto.ts
2import { Exclude, Expose, Transform } from 'class-transformer';
3
4export class LegionaryResponseDto {
5  @Expose()
6  name: string;
7
8  @Expose()
9  rank: string;
10
11  @Expose()
12  @Transform(({ value }) => value > 10 ? 'Veteranus' : 'Tiro')
13  experienceLevel: string;
14
15  @Exclude()
16  secretMissionCode: string;
17
18  @Exclude()
19  salary: number;
20}

Krok 7 — Konfiguracja ValidationPipe

1// main.ts
2import { NestFactory } from '@nestjs/core';
3import { ValidationPipe } from '@nestjs/common';
4
5async function bootstrap() {
6  const app = await NestFactory.create(AppModule);
7  app.useGlobalPipes(new ValidationPipe({
8    whitelist: true,
9    forbidNonWhitelisted: true,
10    transform: true,
11    transformOptions: {
12      enableImplicitConversion: true,
13    },
14  }));
15  await app.listen(3000);
16}
17bootstrap();

To był kompletny przegląd systemu walidacji w NestJS! Twoje bramy są teraz chronione przez najlepszych strażników w całym Imperium. Gratulacje, legioniście!

Przejdź do CodeWorlds