Swagger를 검색하다 보면 OpenAPI라는 단어가 계속 보일텐데 Nest 공식문서에도 OpenAPI와 Swagger를 같은 용어로 칭하듯 목차가 구성되어 있다.
그래서 OpenAPI가 뭐냐면 쉽게 RESTful API들에 대한 정의라고 보면 될 것 같고, Swagger는 OpenAPI를 구현하기 위한 도구라고 보면 될 것 같다.
그리고 나는 Swagger의 도구 중 Swagger UI를 통해 띄운 내 Api 명세서들을 브라우저에서 볼 수 있게 했다.
Nest에서는 데코레이터를 활용해서 Swagger를 사용할 수 있도록 모듈을 제공해줘서 편리했다.
그럼 시작해보자!
npm install --save @nestjs/swagger
main.ts에 Swagger를 사용한다고 작성해주어야 한다.
import { NestFactory } from '@nestjs/core';
import { SwaggerModule } from '@nestjs/swagger';
import { CreateApiDocument } from './api/v1/swagger/create.document';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const apiDocumentOptions = new CreateApiDocument().initializeOptions();
const apiDocument = SwaggerModule.createDocument(app, apiDocumentOptions);
SwaggerModule.setup('api/v1/docs', app, apiDocument);
await app.listen(8080);
}
bootstrap();
하나씩 살펴보면
전체 문서를 만들기 위해서 SwaggerModule 클래스의 createDocument 메소드를 사용해야 하는데 애플리케이션 인스턴스와 Swagger 옵션 객체를 인수로 주어야 한다.
나는 Swagger 옵션 객체를 따로 클래스로 작성하였다
import { DocumentBuilder } from '@nestjs/swagger'
export class CreateApiDocument {
private readonly doc: DocumentBuilder = new DocumentBuilder();
public initializeOptions() {
return this.doc
.setTitle('Adot-Project') // 문서 제목
.setDescription('Adot-Project-Api-Document') // 문서 설명
.setVersion('1.0') // 문서 버전
.setContact('Hagi', '', 'wndbsgkr@naver.com')
.build()
}
}
setContact에는 이 Api 명세서를 작성한 사람에 대한 정보나 나에게 연락을 원하면 이쪽으로 주세요와 같은 정보를 작성하는 곳이다.
그래서 명시하길 원한다면 OpenAPI 문서중 Contact Object를 보고 작성을 하면 된다.
이렇게 Swagger 옵션 객체를 생성하면 Swagger 클래스의 setup 메소드에 전달해 주면 되는데 이 setup 메소드는 http로 접속시 명세서를 볼 수 있는 path, 애플리케이션 인스턴스, Swagger 옵션 객체를 인자로 받는다.
작성 후 서버를 실행시키고 해당 path(여기선 http://localhost:8080/api/v1/docs)로 접속해보면 위에 작성한 내용이 나타난다
@ApiTags('Video')
@Controller('video')
export class VideoController {
@ApiOperation({
summary: '메인페이지 video list 조회',
description: '사용자가 메인 페이지로 이동하면 최신 동영상과 인기 동영상을 노출'
})
@ApiQuery({
description:
'https://localhost:8900/api/v1/video',
})
@ApiResponse({
status: 200,
description: 'video list 반환',
type: VideoResponseDto
})
@Get()
async getMainVideos() {
}
}
어떤 컨트롤러에 대해서 작성할지를 적어주면 된다. 그럼 해당 컨트롤러의 EndPoint들을 모아서 볼 수 있으므로 보기가 편하다.
각 Api마다 설명을 적어줄 수 있는 데코레이터로 summary property를 통해 해당 Api의 간단한 설명을 적어줄수 있고, description property을 통해 해당 Api를 보면 어떤 상황에 호출되는 Api인지 상세하게 적어줄 수 있다.
각 Api를 호출할 때 필요한 파라미터나 데이터들을 name, type, description, example propery들을 통해 상세히 작성할 수 있다.
@ApiParam({
name: 'id',
description: '각 video가 가지고 있는 고유 id',
example: 2,
type: Number
})
여기서, type property에 Dto를 작성해주면 Swagger-UI상에 스키마가 생성된다.
@ApiBody({
type: VideoUploadDto,
description: 'video 업로드시 request body',
})
각 Api의 응답에 대해 작성할 수 있는 데코레이터로 status property로 상태코드를 작성할 수 있다.
@ApiResponse({
status: 200,
description: 'video list 반환',
type: VideoResponseDto
})
type property에 Dto를 작성한 경우 각 property에 대해 ApiProperty 데코레이터를 달아 Swagger에게 알려주자
import { ApiProperty } from "@nestjs/swagger";
export class VideoUploadDto {
@ApiProperty({
description: 'upload하는 user의 id',
example: '8d7fa89df7ds7afsfaf'
})
id: string;
@ApiProperty({
description: 'upload하는 user의 닉네임',
example: '흐암'
})
nickName: string;
@ApiProperty({
description: 'video를 upload 하고 받은 s3 경로',
example: 'https:// aws~~'
})
url: string;
}
각 Dto의 property에 대해 description, example등의 @ApiProperty의 property를 사용해 설명과 예시를 작성해 줄 수 있으며 여기를 참고하면 enum, default, minium등 많은 property를 활용할 수 있다.
작성하다 보니 코드로 Api 명세서를 작성할 수 있다는건 굉장히 편하지만, 프로젝트 규모가 커지다 보면 Api 명세서에 대해 작성하는 코드도 많아져 불편할 것 같기도 하다.
또한, 위에 기능은 정말 기본적인 기능들로만 작성을 한 것이고, Nest 공식문서에는 Nest에서 Swagger를 다양하게 활용할 수 있는 기능들을 제공하니 잘 참고해서 사용하면 될 것 같다.