Utilizziamo i cookie per migliorare la tua esperienza sul sito
CodeWorlds

Wersjonowanie API - ery Imperium

Tak jak historia Imperium Rzymskiego dzieliła się na ery - Królestwo, Republika, Cesarstwo - tak nasze API może mieć wiele wersji. Wersjonowanie pozwala wprowadzać zmiany bez łamania istniejących integracji.

Wersjonowanie w NestJS

NestJS wspiera trzy strategie wersjonowania:

  1. URI Versioning - wersja w ścieżce URL:
    /v1/legiones
  2. Header Versioning - wersja w nagłówku HTTP
  3. Media Type Versioning - wersja w Content-Type

URI Versioning (najczęściej używane)

1// main.ts
2import { VersioningType } from '@nestjs/common';
3
4async function bootstrap() {
5  const app = await NestFactory.create(AppModule);
6
7  app.enableVersioning({
8    type: VersioningType.URI,
9    defaultVersion: '1',
10  });
11
12  await app.listen(3000);
13}

Wersjonowanie kontrolerów

Po włączeniu wersjonowania, kontrolery mogą deklarować swoją wersję:

1@Controller({ path: 'legiones', version: '1' })
2export class LegionV1Controller {
3  @Get()
4  findAll() {
5    return [{ name: 'Legio X', soldiers: 5000 }];
6  }
7}
8
9@Controller({ path: 'legiones', version: '2' })
10export class LegionV2Controller {
11  @Get()
12  findAll() {
13    return [{
14      name: 'Legio X Gemina',
15      soldiers: 5200,
16      province: 'Pannonia',
17      commander: 'Marcus Aurelius',
18    }];
19  }
20}

Wersjonowanie pojedynczych endpointów

1@Controller('legiones')
2export class LegionController {
3  @Version('1')
4  @Get()
5  findAllV1() {
6    return this.legionService.findAllSimple();
7  }
8
9  @Version('2')
10  @Get()
11  findAllV2() {
12    return this.legionService.findAllDetailed();
13  }
14}

Swagger z wieloma wersjami API

Gdy API ma wiele wersji, warto stworzyć osobne dokumenty Swagger dla każdej wersji:

1async function bootstrap() {
2  const app = await NestFactory.create(AppModule);
3
4  app.enableVersioning({
5    type: VersioningType.URI,
6    defaultVersion: '1',
7  });
8
9  // Dokument dla wersji 1
10  const configV1 = new DocumentBuilder()
11    .setTitle('Imperium API v1')
12    .setDescription('Era Republiki - podstawowe endpointy')
13    .setVersion('1.0')
14    .addBearerAuth()
15    .build();
16
17  const documentV1 = SwaggerModule.createDocument(app, configV1, {
18    include: [LegionV1Module, ProvinceV1Module],
19  });
20  SwaggerModule.setup('api/v1/docs', app, documentV1);
21
22  // Dokument dla wersji 2
23  const configV2 = new DocumentBuilder()
24    .setTitle('Imperium API v2')
25    .setDescription('Era Cesarstwa - rozszerzone endpointy')
26    .setVersion('2.0')
27    .addBearerAuth()
28    .build();
29
30  const documentV2 = SwaggerModule.createDocument(app, configV2, {
31    include: [LegionV2Module, ProvinceV2Module],
32  });
33  SwaggerModule.setup('api/v2/docs', app, documentV2);
34
35  await app.listen(3000);
36}

Grupowanie wersji z tagami

Alternatywnie, możesz użyć tagów do rozróżniania wersji w jednym dokumencie:

1@ApiTags('Legiones v1')
2@Controller({ path: 'legiones', version: '1' })
3export class LegionV1Controller {
4  @ApiOperation({ summary: '[v1] Pobierz legiony' })
5  @Get()
6  findAll() {
7    return this.service.findAllV1();
8  }
9}
10
11@ApiTags('Legiones v2')
12@Controller({ path: 'legiones', version: '2' })
13export class LegionV2Controller {
14  @ApiOperation({ summary: '[v2] Pobierz legiony ze szczegółami' })
15  @Get()
16  findAll() {
17    return this.service.findAllV2();
18  }
19}

Dekorowanie wersji w @ApiOperation

Dobrą praktyką jest oznaczanie wersji w opisach endpointów:

1@ApiOperation({
2  summary: 'Pobierz listę legionów',
3  description: `
4    **Wersja 2.0** - Rozszerzona odpowiedź z lokalizacją i dowódcą.
5    Zastępuje endpoint v1 który zwracał tylko podstawowe dane.
6    Wersja v1 będzie wycofana w Q3 2025.
7  `,
8  deprecated: false,
9})
10@Get()
11findAll() {}

Oznaczanie endpointów jako deprecated

Gdy stara wersja endpointu jest wycofywana:

1@ApiOperation({
2  summary: '[DEPRECATED] Pobierz legiony',
3  description: 'Użyj /v2/legiones zamiast tego endpointu',
4  deprecated: true,
5})
6@Get()
7findAllV1() {
8  return this.service.findAllV1();
9}

Ćwiczenie praktyczne

Skonfiguruj wersjonowanie API z dwoma dokumentami Swagger:

Vai a CodeWorlds