-
OpenAPI TypeGenerator 도입하여 타입 걱정 없이 개발하기Web 2023. 10. 2. 00:11
들어가며
백엔드와 협업을 할 때 API 명세를 보며 해당 API의 주소, Method ,Request, Response 등의 타입을 정의하는 것과
API 스펙이 변경되었을 때 다시 문서를 확인하고 위의 행동을 반복하는 것은 귀찮고 시간이 많이 소요된다
우리 회사에서 어떻게 위의 일을 처리하고 있는지, OpenAPI TypeGenerator가 어떤 도움을 주고 있는지 살펴보려고 한다.
OpenAPI TypeGenerator가 어떤 문제를 해결할 수 있을까?
OpenAPI Typegenerator은 OpenApi specification을 기반으로 여러 가지 데이터 형식을 자동으로 생성할 수 있는 라이브러리이다.
OpenAPI Typegenerator로한번 잘 구축해 두면
타입스크립트를 사용할 때 어쩔 수 없이 거쳐야 하는 프로세스인 타입 정의를 명령어 실행 한 번만으로 간소화할 수 있으며
type-safe 하게 api를 최신버전으로 관리할 수 있어 유지 보수에 상당한 자원이 절약된다 (실제로 많이 체감된다)도입 및 활용 방법
타입 생성 과정은 다음과 같다
- OpenAPI Typegenerator NPM 설치
npm install -D openapi-typescript // or yarn add -D openapi-typescript
- OpenApi specification 정의 작성
프론트엔드에서는 해당 과정을 직접 진행할 일이 없지 않을까 싶다 (대부분 swagger을 사용하고 있기 때문에)
우리는 OpenApi specification을 전달해 주는 api를 따로 제공하여 타입 제너레이트를 할 때마다 받아서 사용하고 있다
만약에 따로 OpenApi specification를 전달받을 수 없다고 해도 API문서 툴에서 다운로드하여 저장하면 된다
- generate 스크립트 명령어 작성 및 실행
tpye generate는 앞으로 두고두고 쓰일 테니 간단히 사용하기 위해서 package.json의 scripts에 다음 명령어를 정의한다
한번 퀵하게 해보고 싶으면 https://api.openapi-generator.tech/api-docs 을 specification 파일에 써볼 수 있다
"scripts": { ... "typegen": "openapi-typescript {specification 파일} --output {생성할 폴더}", ... },
그리고 스크립트를 실행해 준다
npm run typegen yarn run typegen
- 생성된 코드 사용
이 글에서는 이전 프로젝트에서 사용하던 swagger를 사용해 타입 코드를 생성해 볼 예정이다
(swagger v5부터 사용 가능)
정상적으로 스크립트가 실행되었다면 --output에 지정한 폴더에 엄청나게 긴 코드 파일이 생성되어 있을 것이다
openapi-typescript가 생성해 준 type들을 쌩으로 사용하기엔 너무 불편함으로
좀 더 편하게 사용하기 위해서 ts-toolbelt를 사용하겠다npm i -D ts-toolbelt // or yarn add -D ts-toolbelt
open-api에서 뽑아쓸 수 있는 타입 많이 있지만 가장 많이 쓰이는 타입을 뽑아보자면- get 요청 시 필요한 파라미터(parameter) type
- get 요청 시 결과값(response) type
- post 요청시 넣어야 할 body 값 (request body) type
위의 3개 타입만 있다면 대부분 상황에 필요한 타입은 받을 수 있어 이 글에선 여기까지 작성하겠지만
ts-toolbelt를 잘 이해하고 있다면 이것보다 더 잘 커스텀하여 사용할 수 있을듯하다
import type { O } from "ts-toolbelt"; import type { components, paths } from "./openapi"; // get api 에서 사용할 path parameter type export type OpenAPIQueryParameter<T extends keyof paths> = O.Path< paths, [T, "get", "parameters", "query"] >; // get api 에서 리턴할 response type export type OpenAPIQueryResponse<T extends keyof paths> = O.Path< paths, [T, "get", "responses", 200, "content", "application/json"] >; // post api 에 보내야할 resquest body type export type OpenAPIRequestBody<T extends keyof paths> = O.Path< paths, [T, "post", "requestBody", "content", "application/json"] >;
이렇게 잘 정의하였다면 실제로 사용해 보도록 하자
사용해보기
react-query를 사용해 api호출을 해볼 건데 일반적인 흐름은 동일하다
1. react-query로 api 호출하기
const { data } = useQuery({ queryKey: ["test"], queryFn: () => apiClient.get("test"), });
2. 정의한 타입 적용하기
const { data } = useQuery({ queryKey: ["test"], queryFn: () => apiClient.get<OpenAPIQueryResponse<"test">>("test"), });
끝이다
어 이게 끝이라고?
api 주소가 자동완성까지 된다고?
실제로 api를 정의하고 -> interface 정의도하고 -> react-query로 호출하는 과정이 한 개 과정으로 줄어들었다
타입이 잘 추론되고 있는지도 확인해 보면
잘 되고 있는 걸 확인할 수 있다
끝으로
지금까지는 장점과 방법만을 설명했지만 그렇다고 단점이 없지는 않다
실제 약 8개월 정도 사용해 본 바로는1. Swagger api 문서에 타입을 의존하기 때문에 타입이 다르게 오면 백엔드팀에 매번 요청하여 문서를 수정해야 한다는 점
애초에 잘 정의해서 보내줘야 하는 게 맞지만, 사람이 하는 일인지라 실수할 수 있기 때문에 가끔 있는 일이다
이럴 땐 수정될 때까지 빨간 줄을 애써 무시하면서 작업하거나, 작업을 잠시 끊고 다른 작업을 해야 하는데 참 쉽지가 않다
2. paging 처리된 데이터를 받을 때 items 칼럼에 타입이 담아지지 않고 올 수 있다는 점
회사에서도 이 부분을 해결하는데 시간이 좀 걸렸다몇 가지 단점이 있어도 OpenAPI TypeGenerator의 진가는 백엔드에서 api 타입이 변경되었을 때 typegen 한번으로 대응할 수 있다는점 이라고 생각하는데, 뚜렷한 장점이 있어 한번쯤 사용해 볼 만한 방법이라고 생각한다
'Web' 카테고리의 다른 글
왜 실제 웹이 피그마와 달랐을까? line height vs paragraph spacing (1) 2023.11.06 신입 프론트엔드 개발자 취업 3개월 후기 (1) 2023.06.20