๐ŸŽ‰ berenickt ๋ธ”๋กœ๊ทธ์— ์˜จ ๊ฑธ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค. ๐ŸŽ‰
Back
NestJs
42-Swagger

1. Swagger๋ž€?

  • API Documentation์„ ์ œ์ž‘ ํ•  ์ˆ˜ ์žˆ๋Š” ์˜คํ”ˆ์†Œ์Šค ํ”„๋ ˆ์ž„์›Œํฌ๋‹ค
  • ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ API ํ…Œ์ŠคํŠธ๋ฅผ ํ•ด๋ณผ ์ˆ˜ ์žˆ๋Š” UI ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•ด์ค€๋‹ค
  • RESTful API๋ฅผ ๋ฌ˜์‚ฌํ•˜๋Š” ํ‘œ์ค€์ ์ธ ๋ฐฉ๋ฒ•์ธ Open API Specification์„ ๋”ฐ๋ฅธ๋‹ค
  • ํ˜„๋Œ€์— ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” API Documenation ํ”„๋ ˆ์ž„์›Œํฌ์ค‘ ํ•˜๋‚˜๋‹ค
  • NestJS, Spring๋“ฑ ์ธ๊ธฐ์žˆ๋Š” ๋Œ€ํ˜• ํ”„๋ ˆ์ž„์›Œํฌ๋“ค์ด ๊ธฐ๋ณธ์œผ๋กœ ์ง€์›ํ•˜๊ณ  ์žˆ๋‹ค

2. DocumentBuilder

Swagger Documentation์„ ์ดˆ๊ธฐํ™”ํ•˜๊ณ  ์ƒ์„ฑํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋œ๋‹ค

1
import { NestFactory } from '@nestjs/core'
2
import { AppModule } from './app.module'
3
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'
4
5
async function bootstrap() {
6
const app = await NestFactory.create(AppModule)
7
const config = new DocumentBuilder()
8
.setTitle('SNS API')
9
.setDescription('API documentation for SNS project')
10
.setVersion('1.0')
11
.addTag('posts')
12
.build()
13
const document = SwaggerModule.createDocument(app, config)
14
SwaggerModule.setup('api', app, document)
15
await app.listen(3000)
16
}
17
bootstrap()

3. @ApiTags

์—ฌ๋Ÿฌ API๋ฅผ ๊ทธ๋ฃนํ™”ํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋œ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ Controller์— ์ง์ ‘ ์ ์šฉํ•ด์„œ ๊ด€๋ จ ์—”๋“œํฌ์ธํŠธ๋“ค์„ ํ•˜๋‚˜๋กœ ๋ฌถ๋Š”๋‹ค.

1
import { Controller, Get } from '@nestjs/common'
2
import { ApiTags } from '@nestjs/swagger'
3
4
@ApiTags('posts')
5
@Controller('posts')
6
export class PostsController {
7
@Get()
8
findAll(): string {
9
return 'This action returns all posts'
10
}
11
}

4. @ApiOperation

์—”๋“œํฌ์ธํŠธ๊ฐ€ ์–ด๋–ค ์—ญํ• ์„ ํ•˜๋Š”์ง€ ์ •์˜ ํ•  ์ˆ˜ ์žˆ๋‹ค. ์งง์€ ์š”์•ฝ์„ ์ž‘์„ฑํ•˜๋Š”๋ฐ ์ข…์ข… ์‚ฌ์šฉ๋œ๋‹ค.

1
import { Get, Controller } from '@nestjs/common'
2
import { ApiOperation } from '@nestjs/swagger'
3
4
@Controller('posts')
5
export class PostsController {
6
@Get()
7
@ApiOperation({ summary: 'Retrieve all posts' })
8
findAll(): string {
9
return 'This action returns all posts'
10
}
11
}

5. @ApiResponse

์—”๋“œํฌ์ธํŠธ์˜ ์‘๋‹ต์— ๋Œ€ํ•œ ์ •์˜๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ฒฝ์šฐ์˜์ˆ˜์— ๋”ฐ๋ผ ํ•˜๋‚˜ ์ด์ƒ ์ •์˜ ๊ฐ€๋Šฅํ•˜๋‹ค

1
import { Get, Controller } from '@nestjs/common'
2
import { ApiResponse } from '@nestjs/swagger'
3
4
@Controller('posts')
5
export class PostsController {
6
@Get()
7
@ApiResponse({ status: 200, description: 'Successfully retrieved posts.' })
8
@ApiResponse({ status: 404, description: 'Posts not found.' })
9
findAll(): string {
10
return 'This action returns all posts'
11
}
12
}

6. @ApiQuery

API์˜ ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ์— ๋Œ€ํ•œ ์ •์˜๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹ค.

1
import { Controller, Get, Query } from '@nestjs/common'
2
import { ApiQuery } from '@nestjs/swagger'
3
4
@Controller('posts')
5
export class PostsController {
6
@Get()
7
@ApiQuery({ name: 'author', required: false, type: String })
8
findAll(@Query('author') author: string): string {
9
return `This action returns all posts by ${author}`
10
}
11
}

7. @ApiParam

API์˜ Path Parameter์— ๋Œ€ํ•œ ์ •์˜๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹ค

1
import { Controller, Get, Param } from '@nestjs/common'
2
import { ApiParam } from '@nestjs/swagger'
3
4
@Controller('posts')
5
export class PostsController {
6
@Get(':id')
7
@ApiParam({ name: 'id', required: true, type: String })
8
findOne(@Param('id') id: string): string {
9
return `This action returns a post with ID ${id}`
10
}
11
}

8. @ApiBody

API์˜ Body์— ๋Œ€ํ•œ ์ •์˜๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹ค

1
import { Controller, Post, Body } from '@nestjs/common'
2
import { ApiBody } from '@nestjs/swagger'
3
4
class CreatePostDto {
5
title: string
6
content: string
7
author: string
8
}
9
10
@Controller('posts')
11
export class PostsController {
12
@Post()
13
@ApiBody({ type: CreatePostDto })
14
create(@Body() createPostDto: CreatePostDto): string {
15
return `This action adds a new post : ${createPostDto.title}`
16
}
17
}

9. @ApiProperty

Model ๋˜๋Š” DTO์˜ ํ”„๋กœํผํ‹ฐ๋ฅผ ํƒœ๊น… ํ•  ์ˆ˜ ์žˆ๋‹ค

1
import { ApiProperty } from '@nestjs/swagger'
2
3
export class CreatePostDto {
4
@ApiProperty({ example: 'My First Post' })
5
title: string
6
7
@ApiProperty({ example: 'This is the content of the post.' })
8
content: string
9
10
@ApiProperty({ example: 'John Doe' })
11
author: string
12
}

10. @ApiBearerAuth

Bearer ํ† ํฐ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.

1
import { Controller, Get } from '@nestjs/common'
2
import { ApiBearerAuth } from '@nestjs/swagger'
3
4
@Controller('posts')
5
export class PostsController {
6
@Get()
7
@ApiBearerAuth()
8
findAll(): string {
9
return 'This action returns all posts'
10
}
11
}

11. @ApiOAuth2

OAuth๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์‚ฌ์šฉ ํ•  ์ˆ˜ ์žˆ๋‹ค

1
import { Controller, Get } from '@nestjs/common'
2
import { ApiOAuth2 } from '@nestjs/swagger'
3
4
@Controller('posts')
5
export class PostsController {
6
@Get()
7
@ApiOAuth2(['read', 'write'])
8
findAll(): string {
9
return 'This action returns all posts'
10
}
11
}

12. ์ ์šฉ ์˜ˆ์ œ

ํ•„์š”ํ•œ ๊ธฐ๋Šฅ๋“ค์„ Annotate ํ•˜๋‹ค๋ณด๋ฉด ์ฝ”๋“œ๊ฐ€ ๋งค์šฐ ๋ณต์žกํ•ด์ง„๋‹ค. ํŠนํžˆ๋‚˜ ๊ธฐ๋Šฅ๊ณผ ๊ด€๋ จ ์—†๋Š” Annotation์ด๋‹ค๋ณด๋‹ˆ ๊ด€๋ฆฌ๊ฐ€ ๋ถ€๋‹ด๋œ๋‹ค

1
class CreatePostDto {
2
@ApiProperty({ example: 'My First Post' })
3
title: string
4
5
@ApiProperty({ example: 'This is the content of the post.' })
6
content: string
7
8
@ApiProperty({ example: 'John Doe' })
9
author: string
10
}
11
12
@ApiTags('posts')
13
@Controller('posts')
14
export 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.' })
19
findAll(@Query('author') author: string): string {
20
return `This action returns all posts by ${author}`
21
}
22
23
@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.' })
28
findOne(@Param('id') id: string): string {
29
return `This action returns a post with ID ${id}`
30
}
31
32
@Post()
33
@ApiOperation({ summary: 'Create a new post' })
34
@ApiBody({ type: CreatePostDto })
35
@ApiResponse({ status: 201, description: 'The post has been successfully created.' })
36
create(@Body() createPostDto: CreatePostDto): string {
37
return `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
}