NestJS Swagger Docs

Swagger generates interactive API documentation automatically from your NestJS code. Instead of writing and maintaining a separate API documentation file, you add decorators to your controllers and DTOs, and Swagger produces a live, browsable documentation page that shows every endpoint, what data it accepts, what it returns, and lets you send real test requests directly from the browser.

What Swagger Gives You

Without Swagger:
  - Write API docs manually in Google Docs or Notion
  - Docs go out of sync with code changes
  - Frontend devs guess request/response shapes
  - Testing requires Postman setup per developer

With Swagger:
  - Docs auto-generated from code annotations
  - Always current — changes to code update docs immediately
  - Interactive: test endpoints from the browser
  - Machine-readable OpenAPI JSON for code generators

Installing Swagger

npm install @nestjs/swagger

Setting Up Swagger in main.ts

// main.ts
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(new ValidationPipe({ whitelist: true, transform: true }));

  const config = new DocumentBuilder()
    .setTitle('My App API')
    .setDescription('API documentation for My App')
    .setVersion('1.0')
    .addBearerAuth()     // adds JWT Authorization header to Swagger UI
    .build();

  const document = SwaggerModule.createDocument(app, config);
  SwaggerModule.setup('api', app, document);
  // Docs available at http://localhost:3000/api

  await app.listen(3000);
}

Swagger UI Screenshot Description

http://localhost:3000/api shows:

MY APP API  v1.0
─────────────────────────────────────────
USERS                      [collapse]
  GET    /users             Get all users
  POST   /users             Create a user
  GET    /users/{id}        Get user by ID
  PATCH  /users/{id}        Update a user
  DELETE /users/{id}        Delete a user

AUTH                       [collapse]
  POST   /auth/login        Login
  POST   /auth/register     Register

[Each endpoint is expandable → shows request body schema, response examples, and a "Try it out" button]

Controller Decorators

import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';

@ApiTags('users')          // groups routes under "users" section
@ApiBearerAuth()           // shows lock icon — JWT required
@Controller('users')
export class UsersController {

  @ApiOperation({ summary: 'Get all users' })
  @ApiResponse({ status: 200, description: 'Returns array of users' })
  @ApiResponse({ status: 401, description: 'Unauthorized' })
  @Get()
  @UseGuards(JwtAuthGuard)
  findAll() { ... }

  @ApiOperation({ summary: 'Get user by ID' })
  @ApiResponse({ status: 200, description: 'Returns the user', type: User })
  @ApiResponse({ status: 404, description: 'User not found' })
  @Get(':id')
  findOne(@Param('id') id: string) { ... }
}

DTO Decorators — Documenting Request Bodies

import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';

export class CreateUserDto {
  @ApiProperty({
    description: 'The full name of the user',
    example: 'Alice Smith',
    minLength: 2,
    maxLength: 100,
  })
  @IsString()
  @IsNotEmpty()
  name: string;

  @ApiProperty({
    description: 'A valid email address',
    example: 'alice@example.com',
  })
  @IsEmail()
  email: string;

  @ApiProperty({ description: 'Age in years', minimum: 1, maximum: 120, example: 30 })
  @IsInt()
  age: number;

  @ApiPropertyOptional({ description: 'User role', enum: ['user', 'admin'], default: 'user' })
  @IsOptional()
  @IsString()
  role?: string;
}

Response Type Annotation

@ApiResponse({
  status: 201,
  description: 'User created successfully',
  type: UserResponseDto,    // Swagger shows the response schema
})
@Post()
create(@Body() dto: CreateUserDto): Promise<UserResponseDto> {
  return this.usersService.create(dto);
}

Documenting Authentication Flow in Swagger

// 1. Call POST /auth/login — copy the access_token from response
// 2. Click "Authorize" button at top of Swagger UI
// 3. Enter: Bearer eyJhb...
// 4. Click Authorize — all locked endpoints now send the token automatically

OpenAPI JSON Export

Swagger also exposes the raw OpenAPI specification as JSON:

GET http://localhost:3000/api-json
→ Returns the complete OpenAPI 3.0 spec as JSON

This file can be:
  - Imported into Postman as a collection
  - Used by code generators to create typed client SDKs
  - Uploaded to API management platforms (AWS API Gateway, Apigee)
  - Shared with frontend teams for automatic TypeScript type generation

Hiding Swagger in Production

// Only enable Swagger in non-production environments
if (process.env.NODE_ENV !== 'production') {
  const document = SwaggerModule.createDocument(app, config);
  SwaggerModule.setup('api', app, document);
}

Swagger documentation transforms your API from a black box into a self-explaining, testable interface. Frontend developers stop asking "what does this endpoint return?" and start reading the docs. New team members onboard faster. API contracts get validated before any code is written. For a few lines of configuration and a handful of decorators, Swagger delivers a documentation system that stays accurate automatically because it reads directly from your code.

Leave a Comment

Your email address will not be published. Required fields are marked *