* 본 포스팅 내용은 2024.09에 실적용한 기술이며, 도입 과정에서 작성해둔 내용을 기반으로 서술하였습니다.
✏️ 기술을 도입하게 된 계기
사내 첫 in-house service 예정 프로젝트를 개발하는 과정에서 생긴 문제로, MVP개발 단계이기 때문에 잦은 수정으로 프론트/백엔드 개발자 간 소통이 잦았으며, 매우 중요하기도 했습니다.
둘 중 한 포지션에서 실수를 하거나 변경사항을 전달하지 못한다면 오히려 소통의 비용이 더 늘어나고 작업기간 지속 지연되는 문제가 있었습니다.
문제점 요약
- Swagger 문서와 실제 API 타입 간 불일치
- 백엔드 스펙 변경 시 프론트엔드 타입을 직접 수정해야 하는 번거로움
- 매번 axios 호출 함수를 수동 작성 → 반복 작업 증가
- 실수로 인한 타입 오류 및 런타임 에러 발생
결국, API 변경 시마다 "이게 body에 들어가는 필드 맞나요?" 혹은 "string이 아니고 number인가요?" 등의 소통이 반복되었고, 개발 효율이 점점 떨어졌습니다.
DX / UX를 지향하는 저는 다시금 스스로에게 질문을 던졌습니다.
"이러한 문제를 어떻게 해결할 수 있을까?"
취업준비 기간에 만든 풀스택 프로젝트인 🔗ZETE - AI 메모 서비스를 개발할 때 그런 생각을 한적이 있습니다.
api를 만들고 Swagger에 spec을 명시하는데 이걸 다시 프론트엔드로 끌고와서 자동화 할 순 없을까?
병아리 개발자인 내가 이렇게 생각하는 기능이라면 분명히 아득히 먼 선배 개발자들이 모두 만들어 두었을거라는 가정을 가지고 탐색해 보았고 첫번째 검색에서 바로 찾을 수 있었습니다.
그리고 OpenAPI와 openapi-generator-cli 에 대해 알게 되었고 즉시 공식문서를 확인하며 긴 노력 끝에 React + Nest.js를 사용한 프로젝트에 적용시켜 이 후에는 월등히 빠른 속도로 풀스택 개발을 진행할 수 있었습니다.
그렇게 활용했던 openapi-generator-cli 를 도입하면 많은 것이 해결될 것 같다는 생각이 들어 동료과 논의 후 대규모 리팩터링인 만큼 기술건의의 주체인 만큼 책임감을 가지고 업무 외 시간(아무도 개발을 하지 않는 시간)을 활용하여 직접 구축하여 통합 적용했습니다.
🪜 도입과정
가장 먼저 openapi-generator-cli를 설치했습니다.
npm i @openapitools/openapi-generator-cli
🥄 꺼내기 ( Eject )

기존에 찾아내어 적용한 방식대로 설치 후 node_modules에서 templates 파일을 eject하기 위해 jar파일을 찾아내어 복사 후 압축을 풀고 mustache파일을 꺼냈습니다.
🪄 설정파일 & 명령어 추가
openapi-generator-cli 생성 명령어가 워낙 길기도 하고 auth / api 두가지 카테고리로 서버가 분류되어 있기에 작업하기 좋은 환경 즉, DX향상을 위해서 OpenAPI-CLI를 실행시킬 js파일을 아래와 같은 형식으로 구성했습니다.
require("dotenv").config({
path: ".env.production",
});
const { execSync } = require("child_process");
const genObject = {
auth: { url: process.env.SWAGGER_AUTH_URL, path: "./src/libs/openapi/auth" },
api: { url: process.env.SWAGGER_API_URL, path: "./src/libs/openapi/api" },
test: "test",
};
const current = genObject[process.env.GENERATE_TYPE];
// 제너레이트타입이 존재하지 않는 경우
if (!current) {
console.error("GENERATE_TYPE 환경 변수가 설정되지 않았습니다.");
process.exit(1);
}
// 명령어 실행 함수
execSync(
`openapi-generator-cli generate -i ${current.url} -g typescript-fetch -o ${current.path} -c ./openapi.json --skip-validate-spec -t ./src/libs/openapi/templates/${process.env.GENERATE_TYPE}`,
{ stdio: "inherit" },
);
추가적으로 openapi.json, openapitools.json 두가지의 별도 설정파일이 더 있지만 생략했습니다.
명령어를 구성할 때 사내 배포환경이 [ dev, qa, prod ] 총 세가지 환경으로 분기되어 있어 환경마다 각기 다른 script 명령어가 필요했습니다.
다양하게 테스트 하고 실무에 바로 적용하기 위해
카테고리 개별 생성 ( import-auth / import-api ),
전체 생성과 삭제 ( create-api / remove-api ),
전체 삭제 후 전체 생성 ( reset-api )
3가지 스크립트 로직으로 구분짓고 엮어서 자동화 프로세스를 완성시켰습니다.
"import-auth:dev": "dotenv -e .env.development -- cross-env GENERATE_TYPE=auth node openapi-generate.js",
"import-auth:qa": "dotenv -e .env.qa -- cross-env GENERATE_TYPE=auth node openapi-generate.js",
"import-auth:prod": "dotenv -e .env.production -- cross-env GENERATE_TYPE=auth node openapi-generate.js",
"import-api:dev": "dotenv -e .env.development -- cross-env GENERATE_TYPE=api node openapi-generate.js",
"import-api:qa": "dotenv -e .env.qa -- cross-env GENERATE_TYPE=api node openapi-generate.js",
"import-api:prod": "dotenv -e .env.production -- cross-env GENERATE_TYPE=api node openapi-generate.js",
"create-api:dev": "dotenv -e .env.development -- cross-env pnpm run import-auth:dev && pnpm run import-api:dev",
"create-api:qa": "dotenv -e .env.qa -- cross-env pnpm run import-auth:qa && pnpm run import-api:qa",
"create-api:prod": "dotenv -e .env.production -- cross-env pnpm run import-auth:prod && pnpm run import-api:prod",
"remove-api": "rimraf ./src/libs/openapi/api ./src/libs/openapi/auth",
"reset-api:dev": "pnpm run remove-api && pnpm run create-api:dev",
"reset-api:qa": "pnpm run remove-api && pnpm run create-api:qa",
"reset-api:prod": "pnpm run remove-api && pnpm run create-api:prod",
꽤나 장황해 보입니다... dotenv와 각 환경 변수를 활용하여 작성하였습니다.
당시 저의 최선이었지만 분명 더 좋은 방법이 있을 것이라고 생각합니다🥲
🥸 API를 생성하는 템플릿 Mustache 파일 커스텀

이게 뭐지 감도 안잡힌다 느낌이었지만 자세히 보면서 하나하나 주석을 남기며 어떤 부분이 어떤 역할을 하는지, 어떤 구문 어떤 코드를 생성해내는지 등 분석하여 기존 사내 프로세스와 커스텀 펫처 등이 정상작동하도록 templates를 커스텀 했습니다.
당시에는 ai를 제대로 활용하지 못했고 cursor - ai도 사용하지 않았기 때문에 주석을 남기며 [ 생성 / 검토 / 수정 ]을 반복하며 작업했기 때문에 좀 더 고된 경험이었습니다...🥹


이렇게 openapi-generator-cli 를 활용한 api 생성 자동화를 적용하였습니다.
🚩결과
결과적으로는 3가지 이점을 얻을 수 있었습니다.
첫 번째로 불필요한 커뮤니케이션 제거되었습니다.
login api - body에 들어가는 필드 중 validateFlag가 number -> string으로 바뀌었어요!
➔ login api 변경사항 있어 재배포 합니다!
구체적인 설명이 필요 없이 특정 엔드포인트의 재배포 라는 단어만으로 프론트엔드는 npm run reset-api:dev 등의 명령어로 간단하게 수정사항이 반영된 api를 받아 빠르게 직접 확인할 수 있게 되어 커뮤니케이션 리소스가 감소했습니다.
두 번째로 유지보수 편의성이 향상되었습니다.
예시 변경 사항:
login api에서 env: "dev" | "qa" | "prod" 와 같이 req body 필드에 추가하고
response를 env에 따라 level: "noob" | "normal" | "super" 과 같이 내려주어야 하는 추가 기능이 생겼다.
[ Before ]
1. 변경되어야 하는 req의 필드 키 네임과 값의 타입 확인
2. req body에 정의된 interface 수정
3. api의 req body 필드를 변경사항과 동일한 필드로 수정
4. reponse에 정의된 interface 수정
[ After ]
1. npm run reset-api:dev
2. api의 req body 필드를 변경사항과 동일한 필드로 수정
하나하나 수정해 줄 필요 없이 명령어로 리세팅 후 req body만 변경해주면 되기 때문에 편의성이 크게 향상되었습니다.
세 번째로 코드 품질과 일관성이 향상되었습니다.
협업 과정에서 개발자마다 서로 다른 코드 스타일이 혼합되면 일관성이 떨어질 가능성이 높습니다.
그러나 openapi-generator-cli 기반 자동 생성 방식을 도입하면서, 검증된 템플릿을 기반으로 일관성 있는 api 생성이 가능해졌습니다.
'Dev Logs' 카테고리의 다른 글
| [ React + Vite & NginX: Gzip Compression ] 번들 사이즈 최적화로 UX향상 시키기 (2) | 2025.11.22 |
|---|---|
| [ React: PDF Generator ] 맞춤형 PDF 렌더링 성능 최적화 (2) | 2025.11.20 |
| [ Python: Async HTTP ] 사내 LLM 챗봇 서버 비동기 전환을 통한 요청 취소 및 논블로킹 구조 개선기 (2) | 2025.11.15 |
| [ Three.js Camera handling ] Map화면 이탈 현상 막기 (0) | 2025.11.14 |
| [ Error Fix ] Unable to find git in your PATH. (2) | 2025.01.01 |