Every imperial decree had to bear the proper seals and markings - who issued it, what it concerns, and what the consequences are. In NestJS, Swagger decorators serve exactly the same role - they describe our endpoints so that every developer can understand them.
The
@ApiTags() decorator groups endpoints into logical sections. Just as the annals of the Empire were divided into books (Lex Militaris, Lex Tributaria), our API is divided into tags:1import { Controller, Get, Post, Body, Param } from '@nestjs/common';
2import { ApiTags } from '@nestjs/swagger';
3
4@ApiTags('Legiones')
5@Controller('legiones')
6export class LegionController {
7 // All endpoints of this controller
8 // will appear in the "Legiones" section in Swagger UI
9}
10
11@ApiTags('Provinciae')
12@Controller('provinciae')
13export class ProvinceController {
14 // These endpoints will be in the "Provinciae" section
15}You can assign multiple tags to a single controller:
1@ApiTags('Legiones', 'Military')
2@Controller('legiones')
3export class LegionController {}@ApiOperation() describes a single endpoint - what it does and for what purpose:1@ApiTags('Legiones')
2@Controller('legiones')
3export class LegionController {
4 @ApiOperation({
5 summary: 'Get list of legions',
6 description: 'Returns the full list of all Empire legions along with their locations and soldier counts.',
7 })
8 @Get()
9 findAll() {
10 return this.legionService.findAll();
11 }
12
13 @ApiOperation({
14 summary: 'Recruit a new legionary',
15 description: 'Adds a new soldier to the selected legion. Requires a rank and cohort assignment.',
16 })
17 @Post()
18 recruit(@Body() dto: CreateLegionaryDto) {
19 return this.legionService.recruit(dto);
20 }
21}@ApiResponse() defines the possible responses of an endpoint - what status codes it can return and what they mean:1import { ApiResponse } from '@nestjs/swagger';
2
3@ApiOperation({ summary: 'Find legion by ID' })
4@ApiResponse({
5 status: 200,
6 description: 'Legion found',
7})
8@ApiResponse({
9 status: 404,
10 description: 'Legion does not exist',
11})
12@Get(':id')
13findOne(@Param('id') id: string) {
14 return this.legionService.findOne(id);
15}@ApiParam() describes parameters in the URL (route parameters):1import { ApiParam } from '@nestjs/swagger';
2
3@ApiOperation({ summary: 'Get legion by ID' })
4@ApiParam({
5 name: 'id',
6 description: 'Unique identifier of the legion',
7 example: 'legio-x-gemina',
8 type: String,
9})
10@Get(':id')
11findOne(@Param('id') id: string) {
12 return this.legionService.findOne(id);
13}@ApiQuery() describes query parameters (after the ? sign in the URL):1import { ApiQuery } from '@nestjs/swagger';
2
3@ApiOperation({ summary: 'Search legions' })
4@ApiQuery({
5 name: 'province',
6 required: false,
7 description: 'Filter by province',
8 example: 'Pannonia',
9})
10@ApiQuery({
11 name: 'minSoldiers',
12 required: false,
13 description: 'Minimum number of soldiers',
14 type: Number,
15})
16@Get('search')
17search(
18 @Query('province') province?: string,
19 @Query('minSoldiers') minSoldiers?: number,
20) {
21 return this.legionService.search(province, minSoldiers);
22}@ApiBearerAuth() marks an endpoint as protected by JWT authentication:1import { ApiBearerAuth } from '@nestjs/swagger';
2import { UseGuards } from '@nestjs/common';
3
4@ApiBearerAuth('JWT-auth')
5@UseGuards(JwtAuthGuard)
6@ApiOperation({ summary: 'Promote a legionary' })
7@Post(':id/promote')
8promote(@Param('id') id: string) {
9 return this.legionService.promote(id);
10}1@ApiTags('Legiones')
2@Controller('legiones')
3export class LegionController {
4 constructor(private readonly legionService: LegionService) {}
5
6 @ApiOperation({ summary: 'Get all legions' })
7 @ApiResponse({ status: 200, description: 'List of legions' })
8 @Get()
9 findAll() {
10 return this.legionService.findAll();
11 }
12
13 @ApiOperation({ summary: 'Get legion by ID' })
14 @ApiParam({ name: 'id', description: 'Legion ID' })
15 @ApiResponse({ status: 200, description: 'Legion found' })
16 @ApiResponse({ status: 404, description: 'Legion not found' })
17 @Get(':id')
18 findOne(@Param('id') id: string) {
19 return this.legionService.findOne(id);
20 }
21
22 @ApiBearerAuth('JWT-auth')
23 @UseGuards(JwtAuthGuard)
24 @ApiOperation({ summary: 'Recruit a legionary' })
25 @ApiResponse({ status: 201, description: 'Legionary recruited' })
26 @ApiResponse({ status: 401, description: 'Unauthorized' })
27 @Post()
28 recruit(@Body() dto: CreateLegionaryDto) {
29 return this.legionService.recruit(dto);
30 }
31}Add Swagger decorators to the controller managing the provinces of the Empire: