API Documentation
API Documentation (specifically Swagger/OpenAPI) acts as a living contract between the backend and the frontend, providing an interactive UI to explore and test the available REST endpoints.
Overview
Manually writing API documentation in a Wiki or Markdown file is a recipe for disaster; it will become outdated the moment you change a DTO.
NestJS provides a dedicated @nestjs/swagger module that reads your controllers, decorators, and DTOs to automatically generate a fully compliant OpenAPI specification. It then hosts a Swagger UI dashboard where developers can see exactly what endpoints exist and even execute requests directly from their browser.
Key Concepts
- OpenAPI Specification: A standard JSON/YAML format for describing REST APIs.
- Swagger UI: The interactive HTML dashboard that renders the OpenAPI spec.
- Swagger CLI Plugin: A NestJS compiler plugin that automatically infers types from your TypeScript code, saving you from writing dozens of
@ApiProperty()decorators.
Code Examples
1. Bootstrapping Swagger
You initialize the Swagger module in your main.ts file.
// 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);
// 1. Build the base configuration
const config = new DocumentBuilder()
.setTitle('My Awesome API')
.setDescription('The My Awesome API description')
.setVersion('1.0')
.addBearerAuth() // Adds the "Authorize" button to the UI for JWTs
.build();
// 2. Generate the OpenAPI document
const document = SwaggerModule.createDocument(app, config);
// 3. Setup the Swagger UI at the '/api' route
SwaggerModule.setup('api', app, document);
await app.listen(3000);
}
bootstrap();
If you run this app and navigate to http://localhost:3000/api, you will see the interactive Swagger UI.
2. Decorating Controllers and DTOs
To make the documentation useful, you need to describe your endpoints and data models.
// create-cat.dto.ts
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { IsString, IsInt, IsOptional } from 'class-validator';
export class CreateCatDto {
// @ApiProperty tells Swagger this field exists and describes it
@ApiProperty({ description: 'The name of the cat', example: 'Mittens' })
@IsString()
name: string;
@ApiProperty({ minimum: 0, default: 1 })
@IsInt()
age: number;
@ApiPropertyOptional({ description: 'The breed of the cat' })
@IsOptional()
@IsString()
breed?: string;
}
// cats.controller.ts
import { Controller, Post, Body } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';
// Groups these endpoints under "cats" in the UI
@ApiTags('cats')
@Controller('cats')
export class CatsController {
@Post()
@ApiBearerAuth() // Indicates this endpoint requires the JWT configured in main.ts
@ApiOperation({ summary: 'Create a new cat' })
@ApiResponse({ status: 201, description: 'The cat has been successfully created.' })
@ApiResponse({ status: 403, description: 'Forbidden.' })
create(@Body() createCatDto: CreateCatDto) {
return 'Cat created';
}
}
Best Practices
- Use the CLI Plugin: Decorating every single DTO property with
@ApiProperty()is incredibly tedious. NestJS provides a Swagger CLI plugin innest-cli.jsonthat reads your TypeScript types and automatically generates the Swagger metadata for you. You should almost always enable this plugin. - Hide in Production: You usually do not want to expose your entire API schema to the public internet. Ensure you conditionally initialize
SwaggerModule.setup()only ifprocess.env.NODE_ENV !== 'production', or put the route behind a basic authentication guard.