1. Swagger๋?
- API Documentation์ ์ ์ ํ ์ ์๋ ์คํ์์ค ํ๋ ์์ํฌ๋ค
- ์ฌ์ฉ์๊ฐ ์ง์ API ํ ์คํธ๋ฅผ ํด๋ณผ ์ ์๋ UI ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํด์ค๋ค
- RESTful API๋ฅผ ๋ฌ์ฌํ๋ ํ์ค์ ์ธ ๋ฐฉ๋ฒ์ธ Open API Specification์ ๋ฐ๋ฅธ๋ค
- ํ๋์ ๊ฐ์ฅ ๋ง์ด ์ฌ์ฉํ๋ API Documenation ํ๋ ์์ํฌ์ค ํ๋๋ค
- NestJS, Spring๋ฑ ์ธ๊ธฐ์๋ ๋ํ ํ๋ ์์ํฌ๋ค์ด ๊ธฐ๋ณธ์ผ๋ก ์ง์ํ๊ณ ์๋ค
2. DocumentBuilder
Swagger Documentation์ ์ด๊ธฐํํ๊ณ ์์ฑํ๋๋ฐ ์ฌ์ฉ๋๋ค
1import { NestFactory } from '@nestjs/core'2import { AppModule } from './app.module'3import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'45async function bootstrap() {6const app = await NestFactory.create(AppModule)7const config = new DocumentBuilder()8.setTitle('SNS API')9.setDescription('API documentation for SNS project')10.setVersion('1.0')11.addTag('posts')12.build()13const document = SwaggerModule.createDocument(app, config)14SwaggerModule.setup('api', app, document)15await app.listen(3000)16}17bootstrap()
3. @ApiTags
์ฌ๋ฌ API๋ฅผ ๊ทธ๋ฃนํํ๋๋ฐ ์ฌ์ฉ๋๋ค. ์ผ๋ฐ์ ์ผ๋ก Controller์ ์ง์ ์ ์ฉํด์ ๊ด๋ จ ์๋ํฌ์ธํธ๋ค์ ํ๋๋ก ๋ฌถ๋๋ค.
1import { Controller, Get } from '@nestjs/common'2import { ApiTags } from '@nestjs/swagger'34@ApiTags('posts')5@Controller('posts')6export class PostsController {7@Get()8findAll(): string {9return 'This action returns all posts'10}11}
4. @ApiOperation
์๋ํฌ์ธํธ๊ฐ ์ด๋ค ์ญํ ์ ํ๋์ง ์ ์ ํ ์ ์๋ค. ์งง์ ์์ฝ์ ์์ฑํ๋๋ฐ ์ข ์ข ์ฌ์ฉ๋๋ค.
1import { Get, Controller } from '@nestjs/common'2import { ApiOperation } from '@nestjs/swagger'34@Controller('posts')5export class PostsController {6@Get()7@ApiOperation({ summary: 'Retrieve all posts' })8findAll(): string {9return 'This action returns all posts'10}11}
5. @ApiResponse
์๋ํฌ์ธํธ์ ์๋ต์ ๋ํ ์ ์๋ฅผ ํ ์ ์๋ค. ๊ฒฝ์ฐ์์์ ๋ฐ๋ผ ํ๋ ์ด์ ์ ์ ๊ฐ๋ฅํ๋ค
1import { Get, Controller } from '@nestjs/common'2import { ApiResponse } from '@nestjs/swagger'34@Controller('posts')5export class PostsController {6@Get()7@ApiResponse({ status: 200, description: 'Successfully retrieved posts.' })8@ApiResponse({ status: 404, description: 'Posts not found.' })9findAll(): string {10return 'This action returns all posts'11}12}
6. @ApiQuery
API์ ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ์ ๋ํ ์ ์๋ฅผ ํ ์ ์๋ค.
1import { Controller, Get, Query } from '@nestjs/common'2import { ApiQuery } from '@nestjs/swagger'34@Controller('posts')5export class PostsController {6@Get()7@ApiQuery({ name: 'author', required: false, type: String })8findAll(@Query('author') author: string): string {9return `This action returns all posts by ${author}`10}11}
7. @ApiParam
API์ Path Parameter์ ๋ํ ์ ์๋ฅผ ํ ์ ์๋ค
1import { Controller, Get, Param } from '@nestjs/common'2import { ApiParam } from '@nestjs/swagger'34@Controller('posts')5export class PostsController {6@Get(':id')7@ApiParam({ name: 'id', required: true, type: String })8findOne(@Param('id') id: string): string {9return `This action returns a post with ID ${id}`10}11}
8. @ApiBody
API์ Body์ ๋ํ ์ ์๋ฅผ ํ ์ ์๋ค
1import { Controller, Post, Body } from '@nestjs/common'2import { ApiBody } from '@nestjs/swagger'34class CreatePostDto {5title: string6content: string7author: string8}910@Controller('posts')11export class PostsController {12@Post()13@ApiBody({ type: CreatePostDto })14create(@Body() createPostDto: CreatePostDto): string {15return `This action adds a new post : ${createPostDto.title}`16}17}
9. @ApiProperty
Model ๋๋ DTO์ ํ๋กํผํฐ๋ฅผ ํ๊น ํ ์ ์๋ค
1import { ApiProperty } from '@nestjs/swagger'23export class CreatePostDto {4@ApiProperty({ example: 'My First Post' })5title: string67@ApiProperty({ example: 'This is the content of the post.' })8content: string910@ApiProperty({ example: 'John Doe' })11author: string12}
10. @ApiBearerAuth
Bearer ํ ํฐ์ด ํ์ํ ๊ฒฝ์ฐ ์ฌ์ฉ ๊ฐ๋ฅํ๋ค.
1import { Controller, Get } from '@nestjs/common'2import { ApiBearerAuth } from '@nestjs/swagger'34@Controller('posts')5export class PostsController {6@Get()7@ApiBearerAuth()8findAll(): string {9return 'This action returns all posts'10}11}
11. @ApiOAuth2
OAuth๊ฐ ํ์ํ ๊ฒฝ์ฐ ์ฌ์ฉ ํ ์ ์๋ค
1import { Controller, Get } from '@nestjs/common'2import { ApiOAuth2 } from '@nestjs/swagger'34@Controller('posts')5export class PostsController {6@Get()7@ApiOAuth2(['read', 'write'])8findAll(): string {9return 'This action returns all posts'10}11}
12. ์ ์ฉ ์์
ํ์ํ ๊ธฐ๋ฅ๋ค์ Annotate ํ๋ค๋ณด๋ฉด ์ฝ๋๊ฐ ๋งค์ฐ ๋ณต์กํด์ง๋ค. ํนํ๋ ๊ธฐ๋ฅ๊ณผ ๊ด๋ จ ์๋ Annotation์ด๋ค๋ณด๋ ๊ด๋ฆฌ๊ฐ ๋ถ๋ด๋๋ค
1class CreatePostDto {2@ApiProperty({ example: 'My First Post' })3title: string45@ApiProperty({ example: 'This is the content of the post.' })6content: string78@ApiProperty({ example: 'John Doe' })9author: string10}1112@ApiTags('posts')13@Controller('posts')14export class PostsController {15@Get()16@ApiOperation({ summary: 'Retrieve all posts' })17@ApiQuery({ name: 'author', required: false, type: String })18@ApiResponse({ status: 200, description: 'Successfully retrieved posts.' })19findAll(@Query('author') author: string): string {20return `This action returns all posts by ${author}`21}2223@Get(':id')24@ApiOperation({ summary: 'Retrieve a specific post by ID' })25@ApiParam({ name: 'id', required: true, type: String })26@ApiResponse({ status: 200, description: 'Successfully retrieved the post.' })27@ApiResponse({ status: 404, description: 'Post not found.' })28findOne(@Param('id') id: string): string {29return `This action returns a post with ID ${id}`30}3132@Post()33@ApiOperation({ summary: 'Create a new post' })34@ApiBody({ type: CreatePostDto })35@ApiResponse({ status: 201, description: 'The post has been successfully created.' })36create(@Body() createPostDto: CreatePostDto): string {37return `This action adds a new post : ${createPostDto.title}`38}39}
13. Open API CLI Plugin
Typescript์ Reflection ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ฉด ์ ์ถ ํ ์ ์๋ ๊ฐ๋ค์ด ๋ง๊ธฐ ๋๋ฌธ์, Open API CLI Plugin์ ์ด์ฉํ๋ฉด ๋ง์ ๊ธฐ๋ฅ๋ค์ ์๋ ์ ์ถ ํ ์ ์๋ค
1{2"collection": "@nestjs/schematics",3"sourceRoot": "src",4"compilerOptions": {5"plugins": ["@nestjs/swagger"]6}7}