OpenAPI 사양은 RESTful API를 설명하기 위해 사용되는 언어에 구애받지 않는 형식이다.
Nest는 데코레이터를 활용하여 이러한 사양을 생성하는 데 사용할 수 있는 전용 모듈을 제공한다.
$ npm install --save @nestjs/swagger
설치 프로세스가 완료되면 main.ts 파일을 열고 SwaggerModule
클래스를 사용하여 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('Cats example')
.setDescription('The cats API description')
.setVersion('1.0')
.addTag('cats')
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document); # 첫번째 인수로 준 문자열 = swagger ui로 접속하기 위한 url
await app.listen(3000);
}
bootstrap();
SwaggerModule#createDocument()
메서드에서 반환된document
는 OpenAPI 문서를 준수하는 직렬화 가능한 객체다. HTTP를 통해 호스팅하는 대신 JSON 또는 YAML 파일로 저장하고 다양한 방식으로 사용할 수 있다.
DocumentBuilder
는 OpenAPI 스펙을 준수하는 기본 문서를 구성하는 데 도움을 줍니다. 제목, 설명, 버전 등과 같은 속성을 설정하는 여러 메서드를 제공한다. 모든 HTTP 경로가 정의된 전체 문서를 만들기 위해 SwaggerModule
클래스의 createDocument()
메서드를 사용한다. 이 메서드는 응용 프로그램 인스턴스와 Swagger 옵션 객체 두 개의 인수를 사용한다. 또는 SwaggerDocumentOptions
유형이 되어야 하는 세 번째 인수를 제공할 수 있다. Document 옵션 섹션에 자세히 설명되어있다!
문서를 만든 후 setup()
메서드를 호출할 수 있다. 메서드는 다음 인수를 받는다.
이제 다음 명령을 실행하여 HTTP 서버를 시작할 수 있다.
$ npm run start
http://localhost:3000/api
로 이동하면 Swagger UI를 볼 수 있다.
SwaggerModule
은 모든 엔드포인트를 자동으로 반영한다.
Swagger JSON 파일을 생성 및 다운로드하려면 Swagger 문서가
http://localhost:3000/api
아래에 있는 것으로 가정하고http://localhost:3000/api-json
로 이동하십시오.
Warning!!
fastify
와helmet
을 사용하는 경우 CSP(Cross-Site Scripting Protection)에 문제가 발생할 수 있으며 이 충돌을 해결하려면 다음과 같이 CSP를 구성해요.app.register(helmet, { contentSecurityPolicy: { directives: { defaultSrc: [`'self'`], styleSrc: [`'self'`, `'unsafe-inline'`], imgSrc: [`'self'`, 'data:', 'validator.swagger.io'], scriptSrc: [`'self'`, `https: 'unsafe-inline'`], }, }, }); // CSP를 전혀 사용하지 않을 경우 다음과 같이 사용할 수 있습니다. app.register(helmet, { contentSecurityPolicy: false, });
문서를 만들 때 라이브러리의 동작을 미세 조정하기 위한 추가 옵션을 제공할 수 있다.
이러한 옵션은 SwaggerDocumentOptions 유형이어야 하며 다음과 같다.
export interface SwaggerDocumentOptions {
/**
* 명세에 포함할 모듈 목록
*/
include?: Function[];
/**
* 명세에 검사되어야 하는 추가 모델
*/
extraModels?: Function[];
/**
* `true`인 경우 Swagger는 `setGlobalPrefix()` 메서드를 통해 설정한 전역 접두사를 무시합니다.
*/
ignoreGlobalPrefix?: boolean;
/**
* `true`인 경우 Swagger는 `include` 모듈에 의해 가져온 모듈에서도 라우트를 로드합니다.
*/
deepScanRoutes?: boolean;
/**
* `operationId`를 `controllerKey`와 `methodKey`를 기반으로 생성하는 데 사용될 사용자 정의 operationIdFactory
* @default () => controllerKey_methodKey
*/
operationIdFactory?: (controllerKey: string, methodKey: string) => string;
}
예를 들어, 라이브러리가 createUser
대신 UserController_createUser
와 같은 작업 이름을 생성하도록 하려면 다음과 같이 설정할 수 있다.
const options: SwaggerDocumentOptions = {
operationIdFactory: (
controllerKey: string,
methodKey: string
) => methodKey
};
const document = SwaggerModule.createDocument(app, config, options);
Swagger UI를 구성하려면 SwaggerModule#setup
메서드의 네 번째 인수로 ExpressSwaggerCustomOptions
인터페이스를 충족하는 옵션 객체를 전달하여 구성할 수 있다.
export interface ExpressSwaggerCustomOptions {
explorer?: boolean;
swaggerOptions?: Record<string, any>;
customCss?: string;
customCssUrl?: string;
customJs?: string;
customfavIcon?: string;
customSwaggerUiPath?: string;
swaggerUrl?: string;
customSiteTitle?: string;
validatorUrl?: string;
url?: string;
urls?: Record<'url' | 'name', string>[];
patchDocumentOnRequest?: <TRequest = any, TResponse = any> (req: TRequest, res: TResponse, document: OpenAPIObject) => OpenAPIObject;
}
Swagger는 API 문서 자동화 도구이다. 이전의 프로젝트에서 사용한 경험으로는 API 문서를 따로 작성할 필요 없이 코드를 수정하면서 API 문서를 같이 수정할 수 있는 것이 큰 장점이었다.
만약에 코드와 API 문서를 따로 관리하게 되면 코드를 수정하였는데 API 문서 최신화를 잊어버려서 다른 팀원들에게 공유된 API 문서가 실제 API와 다른 문제가 발생할 수 있다.
다른 장점으로는 Swagger는 API를 테스트할 수 있는 화면을 제공한다는 것이다.