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/swaggertypescript
// 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 readyPremium
A concise answer to help you respond confidently on this topic during an interview.