팀에서 API pipeline이 거짓말을 시작할 때 일반적으로 그 순간을 알아볼 수 있습니다. 스키마가 변경되면 생성된 타입이 업데이트되며 불평하지 않고 PR이 초록색으로 가고 somebody는 프론트 엔드에서 오래된 응답 형태를 계속 읽습니다. wrapper가 오류를 숨겨주기 때문입니다. 그게 OpenAPI TypeScript의 문제, 그게 아니라 생성기가 인터페이스를 내뿜는가에 대한 문제입니다.
OpenAPI TypeScript의 유용한 질문은 더 어려운 겁니다. 스키마, 전송, 검증 간에 어떤 계약을 원하고 어떤 부분이 빌드 타임에 빠르게 실패해야 하는지, 그리고 런타임에 누출되는지에 대한 질문입니다. 한 번 프레임을 OpenAPI TypeScript pipeline 선택으로, 이익과 손실이 훨씬 분명해지고, 도구들은 전체 솔루션처럼 행동하지 않습니다.
내용목록
- 생성된 타입이 안전한 API와 같은 것은 아님
- OpenAPI 스펙으로부터 TypeScript 타입을 생성하는 방법
- Pure 타입, Full 클라이언트, 그리고 No Codegen 사이의 선택
- Fetch 또는 Axios와 함께 얇은 타입 클라이언트를 연결하는 방법
- 런타임 검증을 추가하는 방법 (zod, ajv, 또는 io-ts)
- CI에서 생성, 유효성 검사 및 계약 테스트를 넣는 방법
- 유지 관리 가능한 Pipe라인, 성능 및 최종 체크리스트
생성된 타입이 안전한 API과 다르다는 이유
팀원 중 한 명이 옵션 응답 필드를 추가하는 PR를 병합합니다. 생성된 파일은 깨끗하게 업데이트되고 diff는 흥미롭지 않으며 모든 팀원은 다음 단계로 넘어갑니다. 그런 다음 프론트 엔드에서는 이전 형태를 읽어오고, 임시로 cast된 __CAPGO_KEEP_0__ wrapper를 통해 읽어오며 as any생산 환경은 계약이 변경되지 않았던 것처럼 동작하기 시작합니다.
생성된 타입에 대한 함정입니다. TypeScript는 생성된 타입을 소비하는 code만 보호할 수 있습니다만약 전송層이 계약을 다시 지우지 않는다면. OpenAPI 측에서는 스키마만 제공하며, 모든 호출자가 계약을 준수하는지 보장하지는 않습니다. API 연결에 대한 이해를 위한 토론 이것은 여기서 유용하다. 왜냐하면 대화가 단일 도구에서 시스템이 연결되는 방식으로 이동되기 때문이다.
실패의 숨겨진 장소
가장 일반적인 브레이크 포인트는 재미있는 것이 아니라 지루한 것이다. 스키마 드리프트 스키마 드리프트는 OpenAPI 스펙과 실제로 배포된 서비스가 일치하지 않을 때 발생한다. 부분적 커버리지 부분적 커버리지는 스펙이 행복한 경로만 모델링하는 반면 앱이 문서화되지 않은 에지 케이스를 의존하는 경우에 발생한다. 수동으로 작성된 wrapper 수동으로 작성된 wrapper는 특히 alguien이 "빠르게 움직이고" 싶을 때 타입이 약화되는 경우가 많다. 이 경우 somebody는 loose response cast를 사용한다. any 실용적인 규칙:
wrapper가 거짓말할 수 있다면, generator가 당신을 구할 수 없다. __CAPGO_KEEP_0__
TypeScript의 런타임 간격이 있습니다. 컴파일 후 TypeScript 타입이 사라지기 때문에, 잘못된 JSON이 네트워크를 통해 전송될 때 이를 거부할 수 없습니다. 네트워크는 편집기에서 추론한 내용에 관심이 없으며, 그래서 생성된 클라이언트는 더 안전한 API pipeline의 단일层입니다.
보다 광범위한 운영 문제는 보안 및 계약 규율이 아니라 개발자 편의성만을 위한 것입니다. API 계약이 더 큰 앱 라이프사이클에 어떻게 적합하게 들어가는지 구조화된 시각을 원한다면 내부 가이드인 API 앱 스토어 준수에 대한 보안 표준 은 유용한 동반자입니다.
openapi typescript 는 이렇게 생각하는 성숙한 방법입니다. 엄격한 스키마-타입 연결을 제공하는 것은 훌륭하지만, 요청을 검증하지 않으며 런타임 페이로드 형태를 강제하지도 않고, 느슨한 wrapper가 모든 것을 무너뜨리도록 하지도 않습니다. 생성기는 쉽게 20%를 제공하지만, 나머지 부분은 pipeline 설계입니다. 그리고 그곳에서 팀은 신뢰를 얻거나 거짓된 자신감을 쌓습니다. OpenAPI 스펙으로부터 TypeScript 타입을 생성하는 방법
스크린샷: https://openapi-ts.dev

를 사용하면, 결정적인 출력 파일을 생성하여 리뷰어들이 다른 소스 변경과 같이 검토할 수 있습니다. npx openapi-typescript ./openapi.yaml -o ./src/types/api.d.ts 실질적으로 중요하는 플래그
__CAPGO_KEEP_0__
The -o 출력 플래그는 생성된 아티팩트를 명확하게 만드는 데 중요합니다. --immutable 이것은 생성된 타입이 readonly 의도(intent)를 보존하고, 스키마 순서가 의미 없는 변경으로 바뀌더라도 diff가 안정적이게 유지되도록 해줍니다. --alphabetize 이것은 생성된 표면에 enums이 보존되는 대신 unions이 보존되는 것을 선호하는 팀이 있을 때 중요합니다. --enum 프로젝트의 문서는 범위가 명확합니다. 그것은 타입 생성기(type generator)이며, 클라이언트 런타임(client runtime)이나 요청 레이어(request layer)가 아닙니다. 이러한 제한은 가볍고 타입-첫 번째(setup)로 설정하고 싶을 때 도움이 됩니다. 또한 도구의 유지 보수 모델은 도구의 저장소(repository)에서 보여집니다. 이는 오픈 소스 도구가 유지 보수가 활발할 때, 유지 보수 모델이 활발할 때, 프로덕션에서 유지 보수가 가능하다는 것을 보여줍니다. 이에 대한 자세한 내용은
오픈 소스 유지 보수의 경우 에서 설명되어 있습니다.실용적인 읽기 __CAPGO_KEEP_0____CAPGO_KEEP_1__ GitHub repository and CLI documentation.
Wire generation into package.json 명령어는 빌드 스크립트와 함께 존재하고 스펙이 변경될 때마다 실행합니다. CI에서 파일을 재생성하고 스펙이 변경되지 않았는지 확인합니다. git diff 변경 사항이 명시적인 리뷰 작업으로 변환되고 런타임 시 비밀이 아닌 위험으로 변환됩니다.
스키마 쪽도 명령어 라인과 마찬가지로 중요합니다. 프로젝트에서는 compilerOptions.noUncheckedIndexedAccess 이것을 사용하여 safer indexing을 강제하고 call sites에서 safer indexing을 강제합니다. 또한 additionalProperties 혼합된 composition 대신 사용하고 T | undefinedplacement이 불명확할 때 oneOf root에 두어야 합니다. 잘못된 위치에 정의를 두면 생성된 출력에서 사라질 수 있습니다. 한 가지 더 자세한 정보가 나중에 시간을 절약합니다. $defs never produce openapi-typescript 이것이 없으면 스펙의 누락된 세부 정보가 permissive types 아래에 숨겨지지 않고 일찍 노출됩니다. any스펙을 명시적으로 유지하거나 생성기는 명시적인 불확실성을 다시 노출합니다.
지속적인 워크플로는 간단합니다. 스펙을 버전 관리 하에 두고 빌드 시 재생성하고 생성된 파일을 커밋하고 타입 체커가 불일치가 발생하기 전에 anyone이 병합하기 전에 불일치를 노출합니다. 그럼 나머지 pipeline에서 안정적인 계약 경계를 제공합니다.
명령어는 빌드 스크립트와 함께 존재하고 스펙이 변경될 때마다 실행합니다. CI에서 파일을 재생성하고 스펙이 변경되지 않았는지 확인합니다.
Pure Types, Full 클라이언트, 및 No Codegen 사이의 선택
| 패턴 | 빌드 시간 | 출력 파일 | 배포 중량 | 최적 |
|---|---|---|---|---|
| Pure Types에 얇은 wrapper | 빠르다 | 적다 | 작다 | runtime surface가 작은 제어를 원하는 팀 |
| Full 클라이언트 코드 생성 | 느린 | 많이 | 높은 | 빠른 전달과 자동화된 작업을 원하는 팀 |
| 코드 생성 요청 빌더가 없는 | 빠른 | 없음 또는 최소 | 낮은 | 한 코드베이스 앱이 수동으로 전송 로직을 선호하는 |
선택은 "도구가 누가 이기냐"가 아니라 "pipeline 형태가 어떤 repo, 팀, 그리고 API가 얼마나 많은 변화를 겪는지에 맞는지"입니다. 2025년 대규모 OpenAPI 스펙(약 75,000줄, 2MB, 약 1,200개 작업)에 대한 벤치마크에서 75,000줄, 2MB, 약 1,200개 작업, openapi-typescript 약 1.5 초 평균적으로 약 8.0 초 위 @hey-api/openapi-ts, 5.5 초 위 Orval, 그리고 18.1 초 위 Kubb, 또한 단일 출력 파일을 생성하는 것과 16 위 hey-api, 2,719 위 Orval과 3,877 위한 Kubb (성능 상세 정보).
순수 타입은 제어를 선호합니다.
순수 타입 설정은 수동으로 요청 레이어를 작성할 때 런타임이 작고 API 표면이 단순해질 수 있습니다. 이는 번들러에 민감한 프론트 엔드와 spec과 consumer를 모두 소유한 앱에서 중요합니다. 개발자 경험은 단순한 구문만이 아니라는 것을 기억해야 하는 경우, 개발자 경험의角度는 클라이언트 API가 짧고 명확하며 검토 가능한 경우 더 쉽게 판단할 수 있습니다. 개발자 경험의角度 is easier to judge when your client code is short, obvious, and reviewable.
, 그리고
openapi-generator, hey-api, Orval모두 타입 외에 더 많은 것을 시도합니다. 이는 요청 메서드, 모델 및 플러밍이 함께 생성되는 경우 특히 백엔드와 프론트 엔드 팀 간의 큰 전달에서 유용할 수 있습니다. 그러나 성능 테스트에서 명확한 비용은 더 많은 생성된 파일, 더 큰 런타임 표면 및 spec이 커질수록 빌드 충돌의 가능성이 있습니다. Kubb 코드 생성이 없는 경우 지역 리팩터링
타입된 요청 빌더와
__CAPGO_KEEP_0__ fetch wrappers는 shape의 양쪽 끝을 소유한 코드베이스가 API 변경이 밀접하게 조정되는 경우 잘 작동합니다. 단점은 유지 보수 discipline입니다. 프로듀서와 컨슈머 사이에 팀과 저장소가 많아질수록, 수동으로 요청 레이어를 작성하는 경우 contract 테스트를 적극적으로 강제하지 않으면 드리프트가 발생할 가능성이 높습니다.
core 의사 결정 지점은 이념적이지 않습니다. 만약 bundle 비용이 협소한 경우, 순수 타입이 매력적입니다. 만약 팀이 최대로 scaffold를 원하고 출력을 흡수할 수 있다면, 전체 클라이언트는 설정 시간을 줄입니다. 만약 계약을 가까이 유지하고 최소한의 이동 부분을 원한다면, no-codegen 요청 빌더가 올바른 내부 거래일 수 있습니다.
Wiring a Thin Typed Client Around Fetch or Axios

thin wrapper는 생성기가 멈추고 애플리케이션 code이 시작되는 곳입니다. wrapper는 하나의 함수를 노출하고, 타입이 지정된 매개 변수와 쿼리 객체를 받으며, 호출을 전달하여 fetch 또는 주입된 axios 인스턴스에 전달하지 말아야 합니다. 대부분의 프로덕션 설정에서, 그 레이어는 30–60 라인으로 유지됩니다. 왜냐하면 생성된 타입이 이미 대부분의 shape를 포함하고 있기 때문입니다. 여기서의 정신 모델은 유지됩니다: Path 매개 변수는 타입이 지정됩니다.
그래서
- __CAPGO_KEEP_0__ __CAPGO_KEEP_0__
/users/{id}__CAPGO_KEEP_0__ 없이 호출할 수 없습니다.id. - 쿼리 객체는 타입이 유지됩니다. 따라서 옵션 필터가 문자열로 변하지 않습니다.
- 응답 본문은 타입이 유지됩니다. 따라서 code을 파싱할 수 있는 것은 code의 좁은 형태를 기대할 수 있습니다.
그런 wrapper는 의도적으로 재미없습니다. 그것은 재시도, 변환, 또는 인증 정책을 invent하지 않아야합니다. 그것은 타입이 지정된 연산에서 요청을 transport layer로 옮겨주고, 그 후에 타입이 지정된 결과를 다시 올려주어야합니다.
wrapper를 재미없게 유지하고 의존성-light로 유지하거나, 모든 미래의 코드 생성 변경이 앱에 영향을 미치지 않도록 하세요.
공통적인 실패는 __CAPGO_KEEP_0__의 생성된 타입이 wrapper의旧 서명과 일치하지 않아 __CAPGO_KEEP_0__를 patch하는 것입니다. 이것은 녹색 빌드를 구비하고 약한 앱을 구비합니다. 또한 생성기가 노출하고자 했던 계약 위배를 숨깁니다. as any Axios를 선호하는 팀의 경우, 패턴은 동일하지만 transport 구현이 변경됩니다. 더 단순한 브라우저 사이드 __CAPGO_KEEP_0__를 원하는 팀의 경우, __CAPGO_KEEP_0__가 종종 충분합니다. 중요한 것은 요청 함수가 생성된 경로 타입을 받아들이고 타입이 지정된 응답을 반환하는 것이며, 나중에 변형되는 loosely shaped 객체가 아니라는 것입니다.
For teams that prefer Axios, the pattern is the same, only the transport implementation changes. For teams that want simpler browser-side code, fetch __CAPGO_KEEP_0__
타입이 지정된 연산 openapi typescript labor 분리를 제공합니다. 스키마는 spec 에서, 전송은 wrapper 에서, 앱은 타입이 지정된 연산을 대신하여 ad hoc 요청 code.
zod, ajv, 또는 io-ts를 사용한 Runtime Validation 추가
TypeScript 타입은 런타임에서 사라지고, 네트워크는 편집기의 자신감에 관심이 없습니다. 따라서 안전한 패턴은 '타입을 생성하고 기대'가 아니라 '타입을 생성하고 edge에서 불신 데이터가 앱에 들어오는 곳에서 검증'입니다. 생성된 스키마는 참조의 원천이 되고, 라이브러리들처럼 zod, ajv, io-ts 입력 경계를 확인하는 작업을 처리합니다. 컴파일 타임 타입이 처리할 수 없는 경계 검사입니다.
데이터가 들어오는 곳에서 검증하십시오.
React 앱의 경우, 요청이 해결되고 페이로드가 상태에 들어가기 전에 일반적으로 edge입니다. 서버의 경우, 페이로드가 데이터베이스에 기록되거나 비즈니스 규칙에 전달되기 전에 일반적으로 edge입니다. 규칙은 간단합니다. 검증을 경계 근처에 유지하고 기능 code에서 수동 검사를 산재시키지 마십시오.
A zod 형태는 생성된 응답 형태를 반영할 수 있습니다. 대체하지는 않습니다:
import { z } from "zod";
const WeatherForecastSchema = z.object({
date: z.string(),
temperatureC: z.number(),
summary: z.string().nullable(),
temperatureF: z.number().optional(),
});
이 예제는 스키마가 옵션으로 표시한 field를 검증하고, 런타임 검사를 생성된 생성기에 맞춰 유지합니다. ajv 서버에서 높은 처리량 JSON 스키마 검증을 원할 때는 io-ts 팀이 이미 특정 스타일로 운영되고 있는 경우에도 여전히 적합합니다. fp-ts 작성 스타일.
payload가 앱으로 들어가기 전에 타입 시스템이 이미 무력화되고 버그가 숨을 수 있는 장소가 생기기 때문입니다. JavaScript에 대한 단위 테스트 이 마음가짐과 잘 어울리는 짧은 가이드입니다. 단위 테스트와 경계 검증 모두 잘못된 가정에 대한 오류를 빨리 잡아야 하기 때문입니다.
정확한 계층 구조는 예측 가능합니다. OpenAPI TypeScript 계약을 생성하고, 검증기를 통해 런타임 데이터를 검사한 후, 앱은 code에 의해만 데이터를 볼 수 있습니다. 이는 정적 타입이 불신스러운 응답을 관리하기 위해 경찰 역할을 하는 것보다 훨씬 더 좋은 경계입니다.
생성, 검증, 계약 테스트를 CI에 넣기

pipeline이 지속되면 계약을 게이트로 바꾸고, 드리프트가 발생하면 실패하고, __CAPGO_KEEP_0__ 형태를 모킹 또는 계약 도구와 연동하여 merge하기 전에 실행하십시오. 만약 생성기 버전을 pin하면... tsc --noEmitAPI package.json두 엔지니어가 같은 스펙에서 다른 출력을 의도적으로 만들 수 없도록 합니다.
A simple GitHub Actions shape
A 실제적인 워크플로는 다음과 같습니다.
- 리포지토리나 생성된 소스에서 스펙을 Pull합니다.
- 타입을 다시 생성합니다.
- 만약에
git diff변경이 보인다면 - 실행합니다.
tsc --noEmit. - Mock 서버를 사용하여 Prism 또는 Spectral-backed 체크를 실행하는 계약 테스트를 수행합니다.
계약 테스트와 스냅샷 테스트의 주요 차이점은 범위입니다. 스냅샷 테스트는 파일이 변경되었는지 알려주지만 계약 테스트는 스펙에 따라 스펙이 어떻게 동작해야 하는지 알려줍니다.
A mock server is especially useful when backend and frontend work are separated by time or team boundaries. It gives consumer code a predictable API surface while still checking the actual contract rather than a hard-coded fixture. The 연속적 통합 설정 가이드 소프트웨어 개발 프로젝트를 위한 OpenAPI TypeScript pipeline을 유지 관리하는 데 필요한 4 가지 주요 단계를 보여주는 체크리스트입니다.
코드 생성 PIPELINE의 한가운데에 있는 가장 끔찍한 실패 중 하나를 피하기 위해 generator 버전을 고정하는 것이 좋습니다. 개발자가 로컬에서 generator를 업그레이드하고 다른 개발자가 업그레이드하지 않으면, 생성된 파일은 신호 대신 랜덤한 잡음이 됩니다. CI는 그럴 수 없습니다.
schema 변경, 타입 생성, 컴파일러 검사 및 계약 테스트 모두가 서로를 강화하는 PIPELINE이 결과입니다. 그것이 워크플로우가 진실되게 만드는 것입니다.
유지 보수 가능한 PIPELINE, 성능, 마지막 체크리스트

The pipelines that survive are the ones with boring governance. Version the spec, review schema changes like code, pin the generator, and document how breaking changes get approved. If the process is fuzzy, people will route around it, and then the generated types become decoration instead of enforcement.
몇 가지 성능 조절자가 실제로 중요합니다.
모노레포에서 스펙이 자주 변경되지만 오직 하나의 패키지만 소비하는 경우 incremental generation이 도움이 됩니다. tsc --incremental 생성된 타입의 크기를 작게 유지하기 위해 반복적인 컴파일러 작업을 생략하고, 프로덕션 빌드에서 필요하지 않은 출력 플래그를 비활성화할 수 있습니다. 실제로 가장 큰 이익은 여전히 사회적이지 않은 기술적이지 않습니다. 예측 가능한 PIPELINE은 더 자주 실행되며, 똑똑한 PIPELINE은 그렇지 않습니다.
아래의 체크리스트는 기억해야 할 것입니다:
- 버전 고정: CI에서 생성된 파일을 업그레이드하지 않도록 CI에서 생성된 파일을 고정하십시오.
openapi-typescript버전 정보package.json이러한 버전이 다른 기기에서 출력되는 것을 방지합니다. - 스키마 검토: 스펙 변경을 계약 변경으로 간주하고, 유지보수 작업으로 간주하지 않습니다.
- 드리프트 감지: CI에서 재생성하고 diff가 발생하면 실패합니다.
- 에지 검증: 미신뢰할 수 있는 페이로드를 앱 상태나 영속성에 도달하기 전에 파싱합니다.
- 계약 테스트: Run a mock-backed check that proves consumer code still matches the schema.
- 브레이킹-체인지 정책: 형태 변경을 승인하는 사람과 클라이언트에게 알리는 방법을 기록합니다.
A pipeline that includes those gates doesn’t just generate types, it makes the contract visible. That visibility is what keeps teams from trusting a file that only looks safe.
If you’re shipping Capacitor or Electron apps and you want your update pipeline to behave with the same discipline, Capgo gives you a practical way to move JavaScript, CSS, copy, config, and asset fixes quickly without waiting on app store review. Visit Capgo to see how its signed bundles, rollback protection, and release controls fit into a release process that needs speed without losing control.