OpenAPI (알파)
이 페이지는 PageTurner AI로 번역되었습니다(베타). 프로젝트 공식 승인을 받지 않았습니다. 오류를 발견하셨나요? 문제 신고 →
이 패키지는 알파 단계입니다. API가 사전 공지 없이 변경될 수 있습니다.
@trpc/openapi 패키지는 tRPC 라우터에서 OpenAPI 3.1 스펙을 생성합니다. 이 스펙으로 다음을 수행할 수 있습니다:
-
모든 언어에서 타입이 지정된 API 클라이언트 생성
-
Postman이나 Insomnia 같은 HTTP 도구로 tRPC 엔드포인트 호출
-
MCP 서버 같은 AI 에이전트 통합 활성화
설치
bashpnpm add @trpc/openapi
bashpnpm add @trpc/openapi
AI 코딩 에이전트를 사용하는 경우 더 나은 코드 생성을 위해 tRPC 스킬을 설치하세요:
bashnpx @tanstack/intent@latest install
bashnpx @tanstack/intent@latest install
@trpc/openapi는 현재 11.x.x-alpha 형식으로 버저닝되며 최신 tRPC v11 버전과 호환됩니다. 하지만 항상 버전 번호를 맞추는 것을 권장합니다
tRPC 설정 적용
생성기는 기존 라우터에서 바로 작동합니다 — 어노테이션이나 데코레이터가 필요하지 않습니다. 주의해야 할 몇 가지 사항:
-
출력 타입 불필요 — 다른 OpenAPI 도구와 달리
.output()스키마는 선택 사항입니다. 생성기가 구현에서 반환 타입을 자동으로 추론합니다. -
트랜스포머 — 서버에서 데이터 변환기를 사용하는 경우 OpenAPI 클라이언트도 동일한 변환기를 사용해야 합니다. 설정 및 크로스 언어 옵션은 트랜스포머를 참조하세요.
-
구독 — 현재 생성된 스펙에서 제외됩니다. SSE 지원이 계획 중입니다.
-
설명 — 타입, 라우터, 프로시저의 Zod
.describe()호출과 JSDoc 주석은 모두 스펙의description필드로 변환됩니다.
스펙 생성
CLI
bashpnpm exec trpc-openapi ./src/server/router.ts
bashpnpm exec trpc-openapi ./src/server/router.ts
| Option | Default | Description |
|---|---|---|
-e, --export <name> | AppRouter | Name of the exported router type |
-o, --output <file> | openapi.json | Output file path |
--title <text> | tRPC API | OpenAPI info.title |
--version <ver> | 0.0.0 | OpenAPI info.version |
bashpnpm exec trpc-openapi ./src/server/router.ts -o api.json --title "My API" --version 1.0.0
bashpnpm exec trpc-openapi ./src/server/router.ts -o api.json --title "My API" --version 1.0.0
프로그래밍 방식
scripts/generate-openapi.tstsimport { generateOpenAPIDocument } from '@trpc/openapi';const doc = generateOpenAPIDocument('./src/server/router.ts', {exportName: 'AppRouter',title: 'My API',version: '1.0.0',});
scripts/generate-openapi.tstsimport { generateOpenAPIDocument } from '@trpc/openapi';const doc = generateOpenAPIDocument('./src/server/router.ts', {exportName: 'AppRouter',title: 'My API',version: '1.0.0',});
생성기는 라우터의 TypeScript 타입을 정적으로 분석합니다 — 코드를 실행하지 않습니다.
스펙에서 클라이언트 생성
모든 OpenAPI 클라이언트 생성기가 작동해야 하지만, 가장 많이 테스트된 통합은 Hey API입니다.
생성된 클라이언트는 tRPC 프로시저에 매칭되는 타입이 지정된 SDK 함수를 생성합니다:
-
쿼리 →
GET /procedure.path -
뮤테이션 →
POST /procedure.path -
구독은 무시됨 (SSE 지원 예정)
Hey API (TypeScript)
bashpnpm add @trpc/openapi @hey-api/openapi-ts
bashpnpm add @trpc/openapi @hey-api/openapi-ts
기본적으로 OpenAPI로 생성된 클라이언트는 트랜스포머 설정이나 쿼리 파라미터 인코딩 방식을 알지 못합니다. @trpc/openapi/heyapi 패키지는 configureTRPCHeyApiClient 헬퍼를 제공해 이 간극을 메웁니다 — 이 헬퍼는 요청 직렬화, 응답 파싱, 에러 역직렬화를 구성하여 생성된 SDK가 tRPC 엔드포인트와 올바르게 작동하도록 합니다.
트랜스포머 없이
이 경우 Hey API의 CLI나 프로그래밍 방식 API로 클라이언트를 생성할 수 있습니다
bashpnpm exec openapi-ts -i openapi.json -o ./generated
bashpnpm exec openapi-ts -i openapi.json -o ./generated
런타임에 약간의 구성이 필요합니다:
src/usage.tstsimport { configureTRPCHeyApiClient } from '@trpc/openapi/heyapi';import { client } from './generated/client.gen';import { Sdk } from './generated/sdk.gen';configureTRPCHeyApiClient(client, {baseUrl: 'http://localhost:3000',});const sdk = new Sdk({ client });const result = await sdk.greeting({ query: { input: { name: 'World' } } });const user = await sdk.user.create({ body: { name: 'Bob', age: 30 } });
src/usage.tstsimport { configureTRPCHeyApiClient } from '@trpc/openapi/heyapi';import { client } from './generated/client.gen';import { Sdk } from './generated/sdk.gen';configureTRPCHeyApiClient(client, {baseUrl: 'http://localhost:3000',});const sdk = new Sdk({ client });const result = await sdk.greeting({ query: { input: { name: 'World' } } });const user = await sdk.user.create({ body: { name: 'Bob', age: 30 } });
트랜스포머 사용 시 (superjson, devalue 등)
백엔드에서 superjson 같은 데이터 변환기를 사용하는 경우 클라이언트 구성에 반드시 전달해야 합니다. 이 작업을 생략하면 Date, Map, Set 및 기타 비JSON 타입이 자동으로 잘못 변환될 수 있습니다.
먼저 Hey API의 프로그래밍 방식 API로 클라이언트 코드를 생성하세요. 이렇게 하면 createTRPCHeyApiTypeResolvers를 사용해 생성된 타입이 정확한지 보장할 수 있습니다:
src/client.tstsimport { createClient } from '@hey-api/openapi-ts';import { createTRPCHeyApiTypeResolvers } from '@trpc/openapi/heyapi';const openApiJson = './path/to/openapi.json'const outputDir = './generated'await createClient({input: openApiJson,output: outputDir,plugins: [{name: '@hey-api/typescript',// Important: this ensures that your emitted types like Dates are correct'~resolvers': createTRPCHeyApiTypeResolvers(),},{name: '@hey-api/sdk',operations: { strategy: 'single' },},],});
src/client.tstsimport { createClient } from '@hey-api/openapi-ts';import { createTRPCHeyApiTypeResolvers } from '@trpc/openapi/heyapi';const openApiJson = './path/to/openapi.json'const outputDir = './generated'await createClient({input: openApiJson,output: outputDir,plugins: [{name: '@hey-api/typescript',// Important: this ensures that your emitted types like Dates are correct'~resolvers': createTRPCHeyApiTypeResolvers(),},{name: '@hey-api/sdk',operations: { strategy: 'single' },},],});
런타임에 생성된 클라이언트를 트랜스포머로 구성하세요. 그러면 네이티브 타입을 직접 전달하고 역직렬화된 결과를 받을 수 있습니다:
src/usage.tstsimport { configureTRPCHeyApiClient } from '@trpc/openapi/heyapi';import superjson from 'superjson';import { client } from './generated/client.gen';configureTRPCHeyApiClient(client, {baseUrl: 'http://localhost:3000',// Important, this transformer must match your tRPC API's transformer:transformer: superjson,});const sdk = new Sdk({ client });const event = await sdk.getEvent({query: { input: { id: 'evt_1', at: new Date('2025-06-15T10:00:00Z') } },});// event.data.result.data.at is a Date object ✅const created = await sdk.createEvent({body: { name: 'Conference', at: new Date('2025-09-01T09:00:00Z') },});
src/usage.tstsimport { configureTRPCHeyApiClient } from '@trpc/openapi/heyapi';import superjson from 'superjson';import { client } from './generated/client.gen';configureTRPCHeyApiClient(client, {baseUrl: 'http://localhost:3000',// Important, this transformer must match your tRPC API's transformer:transformer: superjson,});const sdk = new Sdk({ client });const event = await sdk.getEvent({query: { input: { id: 'evt_1', at: new Date('2025-06-15T10:00:00Z') } },});// event.data.result.data.at is a Date object ✅const created = await sdk.createEvent({body: { name: 'Conference', at: new Date('2025-09-01T09:00:00Z') },});
다른 생성기나 언어 사용하기
생성된 OpenAPI 스펙은 다음 조건을 충족하는 모든 OpenAPI 호환 클라이언트 생성기와 함께 작동합니다:
-
Date 같은 클래스에 대한 정확한 타입 생성
-
Search Params 및 요청/응답 본문 직렬화 커스터마이징 지원
tRPC 프로토콜과 정확하게 통합하려면 생성된 클라이언트를 다음 두 가지를 수행하도록 설정해야 합니다:
-
트랜스포머 — tRPC API가 트랜스포머를 사용하는 경우, 클라이언트는 동일한 포맷으로 입력을 직렬화하고 출력을 역직렬화해야 함
-
쿼리 입력값 — GET 요청은 입력을 개별 쿼리 파라미터가 아닌
?input=<JSON>형식으로 인코딩함
전체 참조 구현은 Hey API 구성 소스 코드를 참조하세요.
트랜스포머
tRPC 데이터 트랜스포머를 사용하면 Date, Map, Set, BigInt 같은 풍부한 타입을 네트워크로 전송할 수 있습니다. OpenAPI 클라이언트 사용 시, 입력이 올바르게 직렬화되고 출력이 역직렬화되도록 서버와 클라이언트 양측에 동일한 트랜스포머를 구성해야 합니다.
tRPC DataTransformer 인터페이스(serialize/deserialize)를 구현하는 모든 트랜스포머는 configureTRPCHeyApiClient와 호환됩니다. 아래는 테스트된 옵션들입니다.
SuperJSON
TypeScript-to-TypeScript 환경에서 가장 널리 사용되는 트랜스포머입니다. Date, Map, Set, BigInt, RegExp 등을 처리합니다.
bashpnpm add superjson
bashpnpm add superjson
src/server.tstsimport { initTRPC } from '@trpc/server';import superjson from 'superjson';const t = initTRPC.create({ transformer: superjson });
src/server.tstsimport { initTRPC } from '@trpc/server';import superjson from 'superjson';const t = initTRPC.create({ transformer: superjson });
src/client.tstsimport { configureTRPCHeyApiClient } from '@trpc/openapi/heyapi';import superjson from 'superjson';import { client } from './generated/client.gen';configureTRPCHeyApiClient(client, {baseUrl: 'http://localhost:3000',transformer: superjson,});
src/client.tstsimport { configureTRPCHeyApiClient } from '@trpc/openapi/heyapi';import superjson from 'superjson';import { client } from './generated/client.gen';configureTRPCHeyApiClient(client, {baseUrl: 'http://localhost:3000',transformer: superjson,});
전체 엔드투엔드 예제는 superjson 테스트를 참조하세요.
MongoDB 확장 JSON v2
EJSON는 크로스-랭귀지 지원이 필요할 때 좋은 선택입니다. bson npm 패키지는 tRPC DataTransformer에 직접 매핑되는 EJSON.serialize/EJSON.deserialize를 제공합니다.
지원 언어: C, C#, C++, Go, Java, Node.js, Perl, PHP, Python, Ruby, Scala
bashpnpm add bson
bashpnpm add bson
src/transformer.tstsimport { EJSON } from 'bson';import type { TRPCDataTransformer } from '@trpc/server';export const ejsonTransformer: TRPCDataTransformer = {serialize: (value) => EJSON.serialize(value),deserialize: (value) => EJSON.deserialize(value as Document),};
src/transformer.tstsimport { EJSON } from 'bson';import type { TRPCDataTransformer } from '@trpc/server';export const ejsonTransformer: TRPCDataTransformer = {serialize: (value) => EJSON.serialize(value),deserialize: (value) => EJSON.deserialize(value as Document),};
src/client.tstsimport { configureTRPCHeyApiClient } from '@trpc/openapi/heyapi';import { client } from './generated/client.gen';import { ejsonTransformer } from './transformer';configureTRPCHeyApiClient(client, {baseUrl: 'http://localhost:3000',transformer: ejsonTransformer,});
src/client.tstsimport { configureTRPCHeyApiClient } from '@trpc/openapi/heyapi';import { client } from './generated/client.gen';import { ejsonTransformer } from './transformer';configureTRPCHeyApiClient(client, {baseUrl: 'http://localhost:3000',transformer: ejsonTransformer,});
전체 엔드투엔드 예제는 MongoDB EJSON 테스트를 참조하세요.
Amazon Ion
Amazon Ion은 다양한 언어 지원을 갖춘 풍부한 타입의 데이터 포맷입니다. JS/TS에서 tRPC와 직접 작동하도록 TRPCDataTransformer 인터페이스를 지원하지 않으며, 약간의 보일러플레이트 코드가 필요하지만 특정 시스템에 적합할 수 있습니다.
지원 언어: C, C#, D, Go, Java, JavaScript, PHP, Python, Rust
bashpnpm add ion-js
bashpnpm add ion-js
트랜스포머 구현, 보일러플레이트 및 전체 엔드투엔드 예제는 Amazon Ion 테스트를 참조하세요.
커스텀 트랜스포머 작성
serialize 및 deserialize 메서드를 가진 모든 객체가 작동합니다:
tsimport type { TRPCDataTransformer } from '@trpc/server';const myTransformer: TRPCDataTransformer = {serialize: (value) => {/* encode rich types */},deserialize: (value) => {/* decode them back */},};
tsimport type { TRPCDataTransformer } from '@trpc/server';const myTransformer: TRPCDataTransformer = {serialize: (value) => {/* encode rich types */},deserialize: (value) => {/* decode them back */},};
서버에서는 initTRPC.create({ transformer })에, 클라이언트에서는 configureTRPCHeyApiClient(client, { transformer })에 전달하세요. 자세한 내용은 데이터 트랜스포머 문서를 참조하세요.
전체 예제
모든 단계를 통합한 완전한 실행 가능한 프로젝트는 openapi-codegen 예제를 참조하세요.