발단
스웨거를 쓰면서 프론트와 소통을 하는데 있어서 몇 가지 아쉬운 점이 있었다.
- 코드 가독성
실제 로직에 적용되는 코드도 아니고, 그렇다고 테스트코드도 아닌데 컨트롤러에서 한 api당 20줄을 넘어서 스크롤압박이 심했다.
- response에 들어갈 데이터 삽입
db에 정의된대로 정확하게 보내주고 싶지만 이게 여간 귀찮은게 아니였다. 직접 입력하는 것도 그렇고, 그리고 그게 결국 코드 가독성에도 영향을 미치게 되었다.
이 두 가지를 이번에 세팅하며 정리했는데, 한층 만족스러워졌다.
해결 방법
내가 진행한 방법은 크게 두가지다.
1. 프론트에게 알려줄 스웨거 Response를 직접 컨트롤러에서 전부 정의하는 것이 아니라 별도의 함수를 만들어 실제 반환할 입력값만 입력하도록 했다.
2. 그리고 실제 반환할 입력값을 직접 입력하지 않고 더미 데이터를 생성하도록 구현했다.
20줄이 넘던 (데이터에 따라 더 될수도.. ) ApiOkResponse 데코레이터는 어느새 적게는 3줄, 많게는 7줄 안에 정리되었다.
이 스크린샷을 보면 이미 사실 어느정도 감을 잡는 사람도 많을 것 같다. 우측에는 위아래로 비교한 부분을 캡쳐했다.
1. 스웨거 응답값 예시 커스터마이징하여 swagger.util.ts 정리
나는 프론트에 데이터를 크게 3가지로 구분해서 보내고 있다.
- statusCode: 프론트에게 보내줄 상태코드를 나의 의도대로 반환한다.
- message: 상태코드로 구분하기 어려운 api가 있을 수 있어 message를 같이 반환한다.
- data?: 데이터를 보낼 경우 반환한다.
기존에 직접 ApiOkResponse 매개변수에 객체를 넣어서 입력했던 값들을 요약해서 하나의 클래스로 구현했다.
그리고 커스텀한 SwaggerResponse에 crud로 네이밍하여 201, 200, 204 로 보내주도록 만들어뒀고, default 메세지를 보내주었다.
다르게 전송이 필요한 경우가 있어 custom 함수를 default로 하여 직접 statusCode, message, data를 넣을 수 있도록 하고 data는 없을 수 있으니 optional하게 두었다.
export class SwaggerResponse {
static custom(
description: string,
statusCode: number,
message: string,
data?: any
): any {
return {
description,
schema: {
example: {
statusCode,
message,
data,
},
},
};
}
static create(description: string, data: any) {
const statusCode = successCode.CREATED;
const message = successMessage.CREATE_POST_SUCCESS;
return SwaggerResponse.custom(description, statusCode, message, data);
}
static read(description: string, data: any) {
const statusCode = successCode.OK;
const message = successMessage.READ_POST_SUCCESS;
return SwaggerResponse.custom(description, statusCode, message, data);
}
static update(description: string, data: any) {
const statusCode = successCode.OK;
const message = successMessage.READ_POST_SUCCESS;
return SwaggerResponse.custom(description, statusCode, message, data);
}
static delete(description: string) {
const statusCode = successCode.NO_CONTENT;
const message = successMessage.DELETE_POST_SUCCESS;
return SwaggerResponse.custom(description, statusCode, message);
}
}
여기까지만 진행하게 되면 코드가 그렇게 많이 줄지는 않는다. 단순히 똑같이 입력되는 ApiOkResponse 객체의 프로퍼티인 구조만 대신해주는 것이다. 여기서 데이터를 직접 입력하게 되면 결국 스웨거 코드는 줄줄이 길어지게 된다.
그래서 모델을 정의하듯 Swagger Example를 만들어서 Import 할까 했는데, 데이터를 생성해주는 라이브러리를 알게 되어 db의 타입에 맞춰 데이터를 생성해서 보여주기로 했다.
2. Faker 라이브러리를 사용하여 SwaggerExample.util.ts 정리
npm i faker를 하게 되면 좋지 않은 결과를 초래할 수 있으니(구글링하면 금방 나오기 때문에 자세한 설명은 생략한다.. )
아래와 같이 설치해준다.
npm i -D @faker-js/faker
faker 라이브러리에 대해서는 아래 포스팅을 참고하면 좋을듯 하다.
https://www.daleseo.com/js-faker-js/
구현한 코드는 다음과 같다.
import { faker } from "@faker-js/faker";
import { user_cards, user_profile } from "@prisma/client";
const bigint = faker.number.bigInt();
const int10 = faker.number.int({ max: 10 });
const int100 = faker.number.int({ max: 100 });
const date = faker.date.anytime();
export function generateUserCards(): user_cards {
return {
id: bigint,
male_id: bigint,
female_id: bigint,
male_point: int100,
female_point: int100,
male_status: int100,
female_status: int100,
created_at: date,
};
}
export function generateUserProfile(): user_profile {
return {
user_id: bigint,
age: int100,
graduated_state: int100,
school: int100,
job_type: int100,
job_name: int100,
workplace: int100,
residence: int100,
school_status: int10,
job_status: int10,
updated_at: date,
};
}
현재 Prisma 를 사용하고 있는데, Prisma 모델을 가져와서 모델에 정의된 타입대로 입력하도록 해주고, 함수명은 어떤 모델을 데이터로 생성해줄건지 똑같이 네이밍해주었다.
기본적으로는 pk로 bigint를 사용하고 있고, 대부분 int타입이라 최댓값만 지정해서 먼저 정의해두고 가져와서 사용했다.
현재 정의해둔 모델의 타입 이외에도 faker에서 지원하는 기능이 많아서 추후 사용해보려 한다.
(string관련해서 편하게 괜찮은 값들을 얻어낼 수 있다. 위 포스팅을 참고해도 좋겠다.)
위 스크린샷 처럼 함수를 불러와서 스웨거에 적용하고 나면 다음과 같이 스웨거에서 확인할 수 있다.
이게 컨트롤러에서 api마다 각각 들어가고 있었다고 생각하니 아찔하다.
결과
다시 스크린샷을 가져와서 비교해보겠다... 뭐 물론 직접 별도의 파일에 Import하는 것도 두줄에 정리됐겠지만, 미리 타입이나 의도에 맞게 정의해둔 faker메서드를 사용해서 스웨거를 정리하면 직접 입력하는 것보다는 빠르게 정리할 수 있을듯 하다.
'개발 > library, framework' 카테고리의 다른 글
[nginx] 특정 요청에 대한 nginx 500 (0) | 2024.11.06 |
---|---|
[express | axios] socket hang up (1) | 2024.02.25 |
[Draft.js] Unknown DraftEntity key: null 해결방법 (0) | 2024.01.08 |
[React] Recoil 로 변경하기 어려운 상태 관리 방법 (0) | 2024.01.04 |
초보 개발자의 Nest의 repository 구조에 대한 고찰 (0) | 2023.12.17 |