NestJS — Enterprise Node.js

OpenAPI / Swagger Documentation

16 min Lesson 32 of 48

OpenAPI / Swagger Documentation

Good APIs are not just functional — they are discoverable. OpenAPI (the specification) and Swagger UI (the interactive browser interface) give every consumer a live, self-describing contract for your endpoints. NestJS ships first-class support through @nestjs/swagger, which reads your TypeScript decorators and generates the spec automatically.

Installation and setup

npm install @nestjs/swagger

Bootstrap Swagger in main.ts using SwaggerModule and DocumentBuilder:

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('Tasks API') .setDescription('Manage user tasks') .setVersion('1.0') .addBearerAuth() // adds the Authorize button for JWT .build(); const document = SwaggerModule.createDocument(app, config); SwaggerModule.setup('api-docs', app, document); // UI at /api-docs await app.listen(3000); } bootstrap();
Generate once, serve forever. SwaggerModule.createDocument() scans every controller and DTO in your application graph and produces a JSON document conforming to the OpenAPI 3.0 specification. The raw JSON is available at /api-docs-json for tooling integration.

@ApiTags — grouping controllers

Tag a controller so its endpoints are grouped under a named section in the UI:

import { Controller, Get } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; @ApiTags('tasks') @Controller('tasks') export class TasksController { @Get() findAll() { /* ... */ } }

Documenting DTOs with @ApiProperty

@ApiProperty annotates each field of a DTO, giving Swagger the type, description, example value, and validation constraints for the request body schema:

import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { IsString, IsNotEmpty, IsOptional, IsEnum } from 'class-validator'; export enum TaskStatus { OPEN = 'OPEN', IN_PROGRESS = 'IN_PROGRESS', DONE = 'DONE', } export class CreateTaskDto { @ApiProperty({ description: 'Short task title', example: 'Write unit tests' }) @IsString() @IsNotEmpty() title: string; @ApiPropertyOptional({ description: 'Longer description', example: 'Cover all service methods with Jest', }) @IsOptional() @IsString() description?: string; @ApiProperty({ enum: TaskStatus, default: TaskStatus.OPEN }) @IsEnum(TaskStatus) status: TaskStatus; }
Use @ApiPropertyOptional for optional fields. It is shorthand for @ApiProperty({ required: false }) and keeps your DTO annotations concise. Always add an example value — it makes the "Try it out" feature actually useful.

@ApiResponse — documenting return types

Decorate individual route handlers to describe possible HTTP responses, including the shape of the returned data:

import { Get, Param } from '@nestjs/common'; import { ApiOkResponse, ApiNotFoundResponse, ApiUnauthorizedResponse, } from '@nestjs/swagger'; import { Task } from './task.entity'; @Get(':id') @ApiOkResponse({ type: Task, description: 'The task record' }) @ApiNotFoundResponse({ description: 'Task not found' }) @ApiUnauthorizedResponse({ description: 'Missing or invalid JWT' }) findOne(@Param('id') id: string) { return this.tasksService.findOne(id); }

For the entity class itself, annotate its properties the same way you annotate DTO fields:

import { ApiProperty } from '@nestjs/swagger'; export class Task { @ApiProperty({ example: 'f47ac10b-58cc-4372-a567-0e02b2c3d479' }) id: string; @ApiProperty({ example: 'Write unit tests' }) title: string; @ApiProperty({ enum: TaskStatus }) status: TaskStatus; }

@ApiBearerAuth — protecting routes in the UI

When a route requires a JWT, add @ApiBearerAuth() so the Swagger UI sends the token from the Authorize dialog:

import { UseGuards } from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; @ApiTags('tasks') @ApiBearerAuth() @UseGuards(AuthGuard('jwt')) @Controller('tasks') export class TasksController { /* ... */ }
Never expose Swagger in production without authentication. The SwaggerModule.setup() call can be wrapped in a check such as if (process.env.NODE_ENV !== 'production'), or protected behind HTTP basic auth using the customSiteTitle / Express middleware approach. A public Swagger UI leaks your full API surface area to attackers.

Summary

@nestjs/swagger generates an OpenAPI 3.0 document directly from your decorators. Install the package, call SwaggerModule.setup() in main.ts, and then annotate controllers with @ApiTags, DTOs with @ApiProperty, handlers with @ApiResponse variants, and protected routes with @ApiBearerAuth(). The result is a live, interactive Swagger UI that doubles as executable documentation for every API consumer on your team.