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.
NestJS wspiera trzy strategie wersjonowania:
/v1/legiones1// 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}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}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}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}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}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() {}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}Skonfiguruj wersjonowanie API z dwoma dokumentami Swagger: