API 통신을 사용하는 애플리케이션에서 수행되어야 하는 작업 중 하나는 프론트엔드와 백엔드가 어떻게 데이터를 주고 받을지 협의하는 것입니다. 이를 위해 문서화 작업을 수행하는데, 그 방법 중 하나가 Swagger를 사용하여 OpenAPI 사양을 작성하는 것입니다.

백엔드 개발자가 Swagger로 문서화 작업을 진행하면, 프론트엔드 개발자는 이 문서를 참고하여 주고받아야 할 데이터의 구조를 파악할 수 있습니다. 특히 TypeScript를 사용하는 프론트엔드 개발자의 경우, 이 문서를 바탕으로 데이터에 대한 정확한 타입을 지정할 수 있어 더욱 유용합니다.

이렇게 Swagger를 통해 프론트엔드와 백엔드 간의 데이터 구조를 명확히 정의할 수 있지만, 여전히 프론트엔드 개발자가 수동으로 타입을 지정해야 하는 과정이 남아있습니다. 타입을 지정하는건, 사람이 하는 일이기 때문에 시간이 많이 소요되고 오류가 발생할 가능성이 있는 작업입니다. API 스펙이 변경될 때마다 관련된 타입을 수동으로 업데이트해야 하는 번거로움이 있습니다.

이러한 번거로움을 어떻게 해결할 수 있을까요? 저는 프로젝트 위클리를 통해 그 해답을 찾았습니다. 바로 OpenAPI TypeScript입니다. 이번 글에서는 OpenAPI TypeScript 공식 문서를 번역하고, 프로젝트에서 어떻게 활용했는지 다룰 예정입니다.

OpenAPI TypeScript

OpenAPI TypeScript는 OpenAPI 사양을 TypeScript로 변환하여 타입 안전성을 보장하는 라이브러리입니다. OpenAPI 스펙을 기반으로 자동으로 생성된 TypeScript 타입과 클라이언트 코드를 통해 API와의 상호작용을 더욱 간편하고 안전하게 만들 수 있습니다. API 호출 시 발생할 수 있는 오류를 컴파일 단계에서 미리 방지할 수 있어 개발 생산성을 높여줍니다.

주요 기능

  1. 자동 타입 생성: OpenAPI 스펙을 바탕으로 TypeScript 타입을 자동으로 생성합니다. 이를 통해 API 스펙이 변경되더라도 타입을 수동으로 업데이트할 필요가 없습니다.
  2. 호환성: TypeScript가 실행되는 모든 곳에서 사용할 수 있습니다. 어떤 스택이나 프레임워크에서도 작동합니다.
  3. 성능 최적화: 정적 TypeScript 타입을 사용하여 즉각적인 성능을 제공합니다. 런타임 비용이 없고 클라이언트 부하도 발생하지 않습니다.

설치 및 사용법

OpenAPI TypeScript를 설치를 위해서는 프로젝트에서 다음 명령어를 실행해야 합니다.

npm i -D openapi-typescript typescript

설치가 완료되면, OpenAPI 스펙 파일을 TypeScript로 변환하는 스크립트를 작성할 수 있습니다. 저희 프로젝트는 Swagger에서 제공하는 document를 활용했습니다.

image

/v3/api-docs를 클릭하면 JSON 파일을 확인할 수 있는데, 이 파일을 input으로 하여 TypeScript 타입으로 변환시킬 것입니다.

/v3/api-docs 파일이 https://myapi.dev/api/v1/api-docs 에 존재한다고 가정하면 다음과 같은 명령어를 실행할 수 있습니다.

npx openapi-typescript https://myapi.dev/api/v1[/api-docs](https://api.badminton.run/v3/api-docs) -o ./schema/schema.d.ts

이 명령어는 JSON이나 YAML 형식만 input으로 사용 가능합니다.

명령어를 실행하면 귀여운 이모지와 함께 결과물인 schema.d.ts가 생성되었다는 메시지를 볼 수 있습니다.

image

실제로 프로젝트에서도 /schema 에 schema.d.ts 파일이 생성된 것을 확인할 수 있습니다.

image

사용 예시

import type { paths, components } from "./schema.d.ts"; // generated by openapi-typescript

// Schema Obj
type MyType = components["schemas"]["MyType"];

// Path params
type EndpointParams = paths["/my/endpoint"]["parameters"];

// Response obj
type SuccessResponse =
  paths["/my/endpoint"]["get"]["responses"][200]["content"]["application/json"]["schema"];
type ErrorResponse =
  paths["/my/endpoint"]["get"]["responses"][500]["content"]["application/json"]["schema"];

위 코드 예시에서 볼 수 있듯이, OpenAPI TypeScript를 통해 자동으로 생성된 타입을 가져와 사용할 수 있습니다. 이렇게 생성된 타입을 사용하면 API 호출 시 데이터 구조를 정확하게 파악할 수 있으며, TypeScript의 타입 체킹 덕분에 컴파일 단계에서 오류를 미리 확인할 수 있습니다.

OpenApi Fetch

개발 시 API 통신의 request와 response에 대한 타입을 미리 정의합니다. 이는 코드의 타입 안전성을 보장하고, 자동 완성타입 추론 등의 이점을 제공하여 개발자의 실수를 줄이고 더욱 신뢰할 수 있는 코드를 작성할 수 있게 합니다.

OpenAPI Fetch는 OpenAPI 스펙을 기반으로 생성된 TypeScript 타입을 활용하여 API request와 response의 타입을 안전하게 처리합니다. 이 라이브러리의 문법은 TanStack-Query와 같은 인기 있는 라이브러리에서 아이디어를 얻었으며, 불필요한 기능들을 제거하여 6kb의 작은 크기로 최적화되어 있습니다.

더불어, OpenAPI Fetch는 제네릭 타입이나 수동 타입 지정할 필요가 없습니다. 엔드포인트의 요청과 응답 타입이 자동으로 추론되어 사용되며, 이를 통해 타입 안전성이 크게 개선됩니다. 이는 수동으로 타입을 지정할 때 발생할 수 있는 오류를 줄이고, API 호출이 정의된 스펙과 일치하도록 보장합니다. 결과적으로, OpenAPI Fetch를 사용하면 개발자는 API 호출 시 자동 완성과 타입 안전성을 보장받으며 개발 생산성을 크게 향상시킬 수 있습니다.

OpenAPI Fetch는 TanStack-Query와 함께 사용할 수 있는 별도의 라이브러리인 @openapi-fetch/react-query를 제공합니다. 이 라이브러리를 통해 TanStack-Query의 상태 관리 기능과 OpenAPI Fetch의 타입 안전성을 결합하여 사용할 수 있습니다. 이는 React 애플리케이션에서 API 통신을 더욱 효율적이고 안전하게 관리할 수 있게 해줍니다.

마무리하며

OpenAPI TypeScriptopenapi-fetch를 통해 프론트엔드와 백엔드 간의 데이터 통신을 안전하게 관리하고, 타입을 자동으로 생성해줄 수 있습니다. API 통신에서 발생할 수 있는 오류를 줄이고, 개발자들이 더욱 신뢰할 수 있는 코드를 작성할 수 있습니다.

만약 API 스펙 변경 시 수동으로 타입을 업데이트하는 과정이 번거롭고 오류가 발생할 수 있다고 느껴본 적이 있다면, 이 두 라이브러리를 활용해보는 것도 좋을 것 같습니다. 타입 안전성과 자동화를 통해 애플리케이션 개발이 한층 더 간편하고 효율적으로 진행될 것이라 예상합니다. 더 나아가, 이 도구들을 활용해 현재의 작업 흐름를 최적화하고, 협업하는 팀원들과의 커뮤니케이션 또한 개선할 수 있을 것입니다.