Skip to main content
Practice Problems

How to document a NestJS API with Swagger?

NestJS + Swagger (OpenAPI)

NestJS has first-class support for Swagger/OpenAPI documentation through the @nestjs/swagger package. It automatically generates interactive API docs from your decorators, DTOs, and controllers.


Setup

bash
npm install @nestjs/swagger
typescript
// main.ts import { NestFactory } from '@nestjs/core'; import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create(AppModule); const config = new DocumentBuilder() .setTitle('My API') .setDescription('REST API documentation') .setVersion('1.0') .addBearerAuth() // adds Authorization: Bearer header UI .addTag('users') .addTag('auth') .build(); const document = SwaggerModule.createDocument(app, config); SwaggerModule.setup('api/docs', app, document); // → /api/docs await app.listen(3000); } bootstrap();

Documenting DTOs

typescript
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; export class CreateUserDto { @ApiProperty({ example: 'Alice', description: 'Full name', minLength: 2 }) @IsString() name: string; @ApiProperty({ example: 'alice@example.com' }) @IsEmail() email: string; @ApiPropertyOptional({ example: 25, minimum: 18 }) @IsOptional() @IsInt() age?: number; @ApiProperty({ enum: ['user', 'admin'], default: 'user' }) @IsEnum(['user', 'admin']) role: string; }

Documenting Controllers

typescript
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth, ApiParam, ApiQuery } from '@nestjs/swagger'; @ApiTags('users') // groups endpoints under "users" @ApiBearerAuth() // requires JWT in Swagger UI @Controller('users') export class UsersController { @Get() @ApiOperation({ summary: 'Get all users', description: 'Returns paginated list of users' }) @ApiQuery({ name: 'page', required: false, type: Number }) @ApiQuery({ name: 'limit', required: false, type: Number }) @ApiResponse({ status: 200, description: 'Returns users list', type: [UserResponseDto] }) findAll() { ... } @Get(':id') @ApiOperation({ summary: 'Get user by ID' }) @ApiParam({ name: 'id', type: Number }) @ApiResponse({ status: 200, type: UserResponseDto }) @ApiResponse({ status: 404, description: 'User not found' }) findOne(@Param('id') id: string) { ... } @Post() @ApiOperation({ summary: 'Create a new user' }) @ApiResponse({ status: 201, type: UserResponseDto }) @ApiResponse({ status: 400, description: 'Validation error' }) create(@Body() dto: CreateUserDto) { ... } }

Response DTO

typescript
import { Exclude, Expose } from 'class-transformer'; export class UserResponseDto { @ApiProperty() id: number; @ApiProperty() name: string; @ApiProperty() email: string; @Exclude() password: string; // excluded from serialized output }

Serialization with ClassSerializerInterceptor

typescript
// Automatically use response DTOs with @Exclude() / @Expose() @Module({ providers: [ { provide: APP_INTERCEPTOR, useClass: ClassSerializerInterceptor, }, ], }) // Controller @Get(':id') @SerializeOptions({ type: UserResponseDto }) findOne(@Param('id', ParseIntPipe) id: number) { return this.usersService.findOne(id); // password will be excluded }

Summary

@nestjs/swagger auto-generates OpenAPI docs from your TypeScript code. Add @ApiProperty() to DTOs and @ApiOperation(), @ApiResponse(), @ApiTags() to controllers. Navigate to /api/docs during development for an interactive Swagger UI to test your API endpoints.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.

Finished reading?
Practice Problems