We use cookies to enhance your experience on the site
CodeWorlds

Controller Decorators - Seals on Decrees

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.

@ApiTags - Books of Annals

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 - Imperial Decree

@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 - Response Edicts

@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 - Path Parameters

@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 - Query Parameters

@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 - Legion Signum

@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}

Full Controller Example with Decorators

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}

Practical Exercise

Add Swagger decorators to the controller managing the provinces of the Empire:

Go to CodeWorlds