Swagger 모듈 설치
$ npm install --save @nestjs/swagger
swagger 모듈 설치(https://docs.nestjs.com/openapi/introduction)
과거에는 express, fastify로 구분된 것으로 보인다. 현재는 위의 명령어 한방이면 설치가 가능하다.
Swagger 생성 코드
// main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { HttpExceptionFilter } from './common/exceptions/http-exception.filter';
import { ValidationPipe } from '@nestjs/common';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe());
app.useGlobalFilters(new HttpExceptionFilter());
// Swagger 셋업
const config = new DocumentBuilder()
.setTitle('Swagger for Cats')
.setDescription('The cats API description')
.setVersion('1.0')
.build();
const document = SwaggerModule.createDocument(app, config);
// Swagger endpoint : ex) localhost:8000/docs
SwaggerModule.setup('docs', app, document);
const PORT = process.env.PORT;
await app.listen(PORT);
}
bootstrap();
Swagger 확인
localhost:8000/docs 주소로 들어가면 확인할 수 있다. docs 엔드포인트는 위 setup 메소드의 인자로 지정할 수 있다.
nestjs가 컨트롤러를 참고하여 자동으로 만들어 준다.
Swagger API에 서머리 추가
...
@Controller('cats')
@UseInterceptors(SuccessInterceptor)
@UseFilters(HttpExceptionFilter)
export class CatsController {
// catsService 종속성 주입
constructor(private readonly catsService: CatsService) {}
@Get()
getCurrentCat() {
return 'current cat';
}
@ApiOperation({ summary: '회원가입을 위한 API' })
@Post()
async signUp(@Body() body: CatRequestDto) {
return await this.catsService.signUp(body);
}
...
서머리를 추가하고 싶은 API에 ApiOperation 데코레이터를 추가해주면 스웨거에 추가 메모를 남길 수 있다.
/cats POST의 원래 목적은 signUp인데 API 핸들러 이름으로만 그 기능을 파악하기가 어려운 문제를 서머리를 추가함으로서 해결했다. 다른 API 핸들러에도 각자 추가해주자.
Swagger POST API 에서 요청 JSON 샘플 정의하기 -> DTO
POST 요청의 경우 JSON에 어떤 프로퍼티를 채워야할지 알기 어렵다. 이 부분은 DTO를 활용하면 된다.
// src/cats/dto/cats.requrest.dto.ts
import { ApiProperty } from '@nestjs/swagger';
import { IsEmail, IsNotEmpty, IsString } from 'class-validator';
export class CatRequestDto {
// Swagger 샘플 데이터
@ApiProperty({
example: 'example@gmail.com',
description: 'email',
required: true,
})
@IsEmail()
@IsNotEmpty()
email: string;
// Swagger 샘플 데이터
@ApiProperty({
example: '1234!!',
description: 'password',
required: true,
})
@IsString()
@IsNotEmpty()
password: string;
// Swagger 샘플 데이터
@ApiProperty({
example: 'john',
description: 'name',
required: true,
})
@IsString()
@IsNotEmpty()
name: string;
}
DTO에 있는 엔티티에 ApiProperty 데커레이터를 추가하고, 인자로 샘플 데이터를 넣어주면 된다.
Swagger API Response 예상 응답 결과값 샘플 정의하기 -> Controller Hanlder
Response 부분에 내용이 없다. 보낼 데이터 예시를 시각화해주었으니, 응답 받을 데이터의 예시도 보여주자. Controller의 hanlder에 @ApiResponse() 데커레이터를 추가해주면 된다.
...
@Controller('cats')
@UseInterceptors(SuccessInterceptor)
@UseFilters(HttpExceptionFilter)
export class CatsController {
// catsService 종속성 주입
constructor(private readonly catsService: CatsService) {}
@ApiOperation({ summary: '전체 고양이 데이터 조회' })
@Get()
getCurrentCat() {
return 'current cat';
}
@ApiResponse({
status: 500,
description: 'There is something wrong in server',
})
@ApiResponse({
status: 200,
description: 'Request was successful',
type: ReadOnlyDto,
})
@ApiOperation({ summary: '회원가입을 위한 API' })
@Post()
async signUp(@Body() body: CatRequestDto) {
return await this.catsService.signUp(body);
}
...
상태코드 500, 200에 대한 설명을 추가했다. 200의 경우, ReadOnlyDto을 연동해주어서 타입 체킹까지 해주고 있다.
Refactor-OOP: class 상속으로 재사용성 높이기
지금 dto의 엔티티를 하나하나 코딩하고 있다. class 상속 받아오는 방식으로 재사용성을 높여보자.
- 기존 방식 : DTO마다 스웨거 데코레이터 추가
- 새 방식 : Cat 스키마 클래스(스웨거 데코레이터 추가) -> DTO가 이를 상속하여 사용
// cats 폴더 내 cats.schema.ts
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { ApiProperty } from '@nestjs/swagger';
import { IsEmail, IsNotEmpty, IsString } from 'class-validator';
import { Document, SchemaOptions } from 'mongoose';
const options: SchemaOptions = {
timestamps: true,
};
@Schema(options)
export class Cat extends Document {
// 재사용상 향상을 위한 swagger 적용
@ApiProperty({
example: 'example@gmail.com',
description: 'email',
required: true,
})
@Prop({
required: true,
unique: true,
})
@IsEmail()
@IsNotEmpty()
email: string;
@ApiProperty({
example: 'john',
description: 'name',
required: true,
})
@Prop({
required: true,
})
@IsString()
@IsNotEmpty()
name: string;
@ApiProperty({
example: '1234!!',
description: 'password',
required: true,
})
@Prop({
required: true,
})
@IsString()
@IsNotEmpty()
password: string;
@Prop()
@IsString()
imgUrl: string;
// 가상 엔티티 추가
readonly readOnlyData: { id: string; email: string; name: string };
}
// Cat 클래스를 CatSchema 스키마로 생성
export const CatSchema = SchemaFactory.createForClass(Cat);
// virtual 메소드로 가상 엔티티 생성. 불필요한 password는 숨김처리하기 위함
CatSchema.virtual('readOnlyData').get(function (this: Cat) {
// this라는 DB 객체에서 id, email, name을 추출
return {
id: this.id,
email: this.email,
name: this.name,
};
});
// src/cats/dto/cats.requrest.dto.ts
import { PickType } from '@nestjs/swagger';
import { Cat } from '../cats.schema';
export class CatRequestDto extends PickType(Cat, [
'email',
'name',
'password',
] as const) {
// DTO 내용은 Cat 스키마에서 모두 상속
}
// cats.dto.ts
import { ApiProperty, PickType } from '@nestjs/swagger';
import { Cat } from '../cats.schema';
export class ReadOnlyDto extends PickType(Cat, ['email', 'name'] as const) {
// 나머지는 Cat에서 상속
// Cat에서 password 가져오지 않기 위해 PickType 사용
// 몽구스에서 자동 생성하는 id를 위한 Swagger 샘플 데이터
@ApiProperty({
example: '1224124',
description: 'email',
})
id: string;
}
'Research > Nest.js' 카테고리의 다른 글
nestjs_repository 추가하기 (0) | 2023.04.06 |
---|---|
nestjs_CORS 허용하기 (0) | 2023.04.05 |
nestjs_signup api 구현 + virtual 필드로 민감정보는 숨기기 (0) | 2023.04.05 |
nestjs_DTO 만들고 붙이기 (0) | 2023.04.05 |
nestjs_mongoose 스키마 설계 후 class-validator 적용 (0) | 2023.04.05 |
댓글