Как настроить Swagger (OpenAPI) в NestJS?
Установка и базовая настройка
Для интеграции Swagger в NestJS используется официальный пакет @nestjs/swagger, который генерирует документацию на основе декораторов и TypeScript-типов.
npm install @nestjs/swagger
После установки настройка выполняется в 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('API платформы PurpleSchool')
.setDescription('Документация REST API')
.setVersion('1.0')
.addBearerAuth() // добавляем JWT-авторизацию
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api/docs', app, document);
await app.listen(3000);
}
bootstrap();
После запуска документация доступна по адресу http://localhost:3000/api/docs.
Аннотирование контроллеров и DTO
Swagger собирает описание из декораторов, расставленных на контроллерах и DTO-классах.
Контроллер
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';
@ApiTags('Пользователи') // группировка в UI
@ApiBearerAuth() // указывает, что роуты требуют JWT
@Controller('users')
export class UsersController {
@Get(':id')
@ApiOperation({ summary: 'Получить пользователя по ID' })
@ApiResponse({ status: 200, description: 'Пользователь найден', type: UserDto })
@ApiResponse({ status: 404, description: 'Пользователь не найден' })
findOne(@Param('id') id: string) {
return this.usersService.findOne(+id);
}
}
DTO-класс
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
export class CreateUserDto {
@ApiProperty({ example: 'ivan@example.com', description: 'Email пользователя' })
email: string;
@ApiProperty({ example: 'секретный_пароль', minLength: 8 })
password: string;
@ApiPropertyOptional({ example: 'Иван', description: 'Имя пользователя' })
name?: string;
}
Поддержка plugin для автоматической генерации
Chтобы не дублировать @ApiProperty над каждым полем, подключается CLI-плагин в nest-cli.json:
{
"compilerOptions": {
"plugins": ["@nestjs/swagger"]
}
}
Плагин автоматически считывает TypeScript-типы и JSDoc-комментарии, избавляя от необходимости явно указывать @ApiProperty для примитивных полей.
Схемы для Enum и вложенных объектов
import { ApiProperty } from '@nestjs/swagger';
export enum UserRole {
Admin = 'admin',
Student = 'student',
}
export class UserDto {
@ApiProperty({ enum: UserRole, enumName: 'UserRole' })
role: UserRole;
@ApiProperty({ type: () => AddressDto }) // отложенный тип для вложенных объектов
address: AddressDto;
}
Разделение документации по модулям (несколько документов)
Для крупных приложений можно создать несколько Swagger-документов с фильтрацией по тегам:
const adminDocument = SwaggerModule.createDocument(app, config, {
include: [AdminModule], // только роуты AdminModule
});
SwaggerModule.setup('api/admin/docs', app, adminDocument);
Важные практики
- Swagger UI в production рекомендуется отключать или защищать HTTP Basic Auth — документация раскрывает структуру API.
DocumentBuilder.addBearerAuth()нужно сочетать с@ApiBearerAuth()на контроллерах, иначе кнопка «Authorize» в UI не будет применяться к роутам.- Для корректного отображения массивов используйте
@ApiProperty({ type: [ItemDto] })илиisArray: true.
Что хочет услышать интервьюер
Знание пакета @nestjs/swagger и процесса его подключения через DocumentBuilder + SwaggerModule
Понимание декораторов @ApiTags, @ApiOperation, @ApiResponse, @ApiProperty и их назначения
Осведомлённость о CLI-плагине для автоматической генерации метаданных из TypeScript-типов
Понимание необходимости защиты Swagger UI в production-окружении
Умение работать с авторизацией в Swagger: addBearerAuth / addApiKey и @ApiBearerAuth
Пример: Полная настройка Swagger в 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('PurpleSchool API')
.setDescription('Документация REST API платформы')
.setVersion('1.0')
.addBearerAuth(
{ type: 'http', scheme: 'bearer', bearerFormat: 'JWT' },
'JWT-auth', // ключ, используемый в @ApiBearerAuth('JWT-auth')
)
.build();
const document = SwaggerModule.createDocument(app, config);
// отключаем Swagger в production
if (process.env.NODE_ENV !== 'production') {
SwaggerModule.setup('api/docs', app, document);
}
await app.listen(process.env.PORT ?? 3000);
}
bootstrap();
Пример: Аннотированный контроллер и DTO
import { Controller, Post, Body, Get, Param } from '@nestjs/common';
import {
ApiTags,
ApiOperation,
ApiResponse,
ApiBearerAuth,
ApiProperty,
} from '@nestjs/swagger';
export class CreateCourseDto {
@ApiProperty({ example: 'NestJS Pro', description: 'Название курса' })
title: string;
@ApiProperty({ example: 4999, description: 'Цена в рублях' })
price: number;
}
export class CourseDto extends CreateCourseDto {
@ApiProperty({ example: 1 })
id: number;
}
@ApiTags('Курсы')
@ApiBearerAuth('JWT-auth')
@Controller('courses')
export class CoursesController {
@Post()
@ApiOperation({ summary: 'Создать курс' })
@ApiResponse({ status: 201, type: CourseDto })
create(@Body() dto: CreateCourseDto): CourseDto {
return { id: 1, ...dto };
}
@Get(':id')
@ApiOperation({ summary: 'Получить курс по ID' })
@ApiResponse({ status: 200, type: CourseDto })
@ApiResponse({ status: 404, description: 'Курс не найден' })
findOne(@Param('id') id: string): CourseDto {
return { id: +id, title: 'NestJS Pro', price: 4999 };
}
}
Типичные ошибки
Забывают указать @ApiProperty на полях DTO и удивляются, что схема в UI пустая (без плагина аннотации обязательны)
Оставляют Swagger открытым в production без какой-либо защиты
Не используют enumName в @ApiProperty для enum — в схеме генерируются дублирующиеся безымянные enum-типы
Путают @ApiResponse (описание ответа) и @ApiBody (описание тела запроса) — @ApiBody нужен только для нестандартных тел, POST/PUT автоматически подхватывают DTO
Не подключают addBearerAuth() в DocumentBuilder, но расставляют @ApiBearerAuth() — кнопка Authorize в UI присутствует, но не работает


