2025. 07
swagger + openapi-typescript로 any 지옥 탈출하기
타입스크립트는 가끔 지옥이다
- TypeScript
- 리팩토링
- 아키텍처
문제 상황
최근 저는 어떤 사이트의 유지보수 업무를 하고 있는데요, 프론트엔드부터 서버, db, 네트워크까지 전권이 저한테 있는 상황입니다. 프론트엔드의 기술스택은 svelteKit으로 이루어져 있고, 서버는 Strapi CMS를 사용해 개발되어 있었습니다. 전임 개발자와 소통할 수 없었고, 환경변수는 제대로 오지 않아서 모든 아키텍처를 재구축해야 했습니다. 그 중 가장 심각한 것은 타입 문제였습니다. 이 문제를 Swagger + openapi-typescript로 타입 생성을 자동화해 해결한 이야기입니다.
any…any…any…
이 프로젝트에는 다음과 같은 문제가 있었습니다:
프론트엔드 프로젝트의 모든 타입에
any
가 적혀 있는 상태서버 프로젝트가 타입스크립트 컴파일을 하지 않는 채로 개발됨
타입 유틸리티 플러그인이 import만 되고 실제 의존성에서 누락되어 있음
다른 기초적인 타입들에는 모두
any
즉 사이트를 개발할 때 api 스펙을 어떤 곳에서도 참조할 수 없는 상황이었습니다.
OpenAPI Specification (OAS)
OpenAPI Specification (OAS)은 RESTful API를 설명하기 위한 표준이자 오픈 소스 사양입니다. Swagger 외에도 PostMan이 이 스펙에 따라 동작하고요. 이러니저러니 해도 api 개발자와 사용자간의 소통을 위해 만들어진 표준이라고 할 수 있겠습니다. YAML(json)
을 사용(json은 yaml의 하위 집합입니다)하고, 아래와 같은 주요 규칙이 있습니다.
Servers
: API 서버의 URL 정보Paths
: API 엔드포인트 (URL 경로)와 각 엔드포인트의 동작 (HTTP 메서드, 요청/응답 구조 등) 정의Components
: 재사용 가능한 스키마, 응답, 매개변수 등을 정의
이 외에도 요약이나 버전 같은, 메타데이터에 해당하는 필드도 있습니다.
어떤 API가 REST를 따른다면 OAS대로 스펙 문서를 생성하거나, 반대로 스펙 문서에서 구현 인터페이스로 바꾸는 툴이 존재한다는 것이 중요합니다.
OAS 스펙을 타입으로 바꾸기
API 타입을 만드는 데는 다양한 방법이 있습니다. 직접 작성할 수도 있고 자동화할 수도 있는데, 저는 서버 스펙이 변할 때 타입도 자동으로 만들어줄 수 있어야 한다고 판단했습니다. 하나의 프로젝트이기도 하고, 타입스크립트로 개발되어 있었던 만큼 깔끔하게 스펙을 맞춰두면 다음 개발자가 훨씬 더 안정적으로 개발할 수 있다고 생각했기 때문입니다.
Strapi CMS에 Swagger 같은 문서화 플러그인을 먼저 부착하고, API 스펙을 추출한 뒤 OpenAPI Typescript로 타입을 생성하는 것이 충분히 가능할 것이라고 판단했기 때문이기도 합니다. API 스펙을 생성했다면, 타입을 생성하는 것은 쉽게 자동화할 수 있습니다.
openapi-typescript | OpenAPI TypeScript
https://openapi-ts.dev/introduction
npm install openapi-typescript
로 설치하고, Schema JSON에 따라
openapi-typescript {schemapath.json|yaml|...} -o {outputpath}.d.ts
로 타입을 생성해 줍니다.
이 스펙으로 fetch
를 해 주는 openapi-fetch(https://openapi-ts.dev/openapi-fetch/)같은 도구들도 있지만, 저는 우선 타입만 붙이는 것으로 시작했습니다.
타입 사용하기
타입을 만든 다음에는 아래처럼 사용할 수 있습니다. 기본적으로 paths
와 components
를 통해 타입을 가져올 수 있습니다.
type MyResponseType1 = paths['/myresponse']['get']['responses']['200']['content']['application/json'];
type MyResponseType2 = components["schemas"]["MyResponse"]
직관적이죠? 인터페이스를 직접 정의하는 것보다, 서버 측에서 타입 생성을 자동화해 두면 클라이언트에서는 api 문서만 보고 쉽게 어떤 데이터가 올지 예측할 수 있습니다.
왜 타입을 다시?
타입, 또는 api 스펙 문서가 없으면 프로젝트의 아키텍처와 구조를 파악하기 너무나 어렵습니다. 프론트엔드 개발자의 입장에서 props
의 타입이 지원되지 않고, 그에 대한 방어코드가 하나도 작성되어있지 않아 프로젝트를 유지보수하기 난감했습니다. 거기에 프로젝트 구조를 파악할 겸 해서 타입을 붙이는 작업을 하게 됐습니다.
타입을 생성하는 작업은 쉽게 끝났지만, any
로 되어 있는 곳에 이 타입을 붙이고 타입 디버깅을 하는 것은 지난한 작업입니다. 그럼에도 불구하고, 저의 개발 편의는 물론 제 코드를 이어받게 되실 분이 좀더 편하게 개발했으면 하는 마음이 있었고 그 첫 걸음이 API 스펙과 타입이었습니다.
마무리
타입스크립트는 언어지만, 분석 도구로서 컨벤션의 영역에 있기도 합니다. 컴파일 옵션들을 자의적으로 끄고 켤 수 있기 때문입니다. 즉 사용하는 사람에게 많은 부분을 맡기게 됩니다. 타입스크립트를 “제대로” 사용하는 것이 무엇인지 말하기는 힘들지만, “이렇게” 사용하는 건 되려 불편함만 초래한다는 것을 체감할 수 있었습니다.