Summary#
OpenAPI로 TypeScript 클라이언트를 생성할 때의 “schema drift”는 단순히 스펙 파일이 바뀌는 문제가 아니라, 생성기의 해석 차이와 TypeScript 타입 표면 변화가 결합되면서 발생한다. 특히 nullable, oneOf/anyOf/allOf, discriminator, additionalProperties, enum, required, operationId는 SDK의 타입 안정성·런타임 직렬화·메서드 이름·하위 호환성에 직접 영향을 준다.
실무적인 가드레일은 세 층으로 나누는 것이 안전하다.
- OpenAPI spec diff 단계: PR/CI에서 breaking change를 탐지한다.
- SDK generation 단계: OpenAPI Generator 버전과 설정을 고정하고, 생성 결과 diff를 검토한다.
- TypeScript compile/test 단계: 생성된 클라이언트를 실제 소비자 코드 또는 fixture와 함께 컴파일·런타임 검증한다.
핵심은 “스펙이 유효하다”와 “생성된 TypeScript SDK가 호환된다”를 분리해서 검사하는 것이다.
Key Points#
operationId는 API 호환성 표면이다- OpenAPI Specification은
operationId가 API 내에서 고유해야 하며 도구와 라이브러리에서 작업 식별자로 쓰일 수 있다고 설명한다. - TypeScript SDK 생성기에서는
operationId변경이 메서드명 변경으로 이어질 수 있다. - 따라서 endpoint path/method가 유지되더라도
operationId변경은 SDK 소비자 입장에서는 breaking change로 취급하는 것이 안전하다. -
CI guardrail:
operationId누락 금지- 중복 금지
- 기존 operation의
operationId변경 시 breaking label 요구 - 생성된 SDK public method diff 확인
-
required변경은 TypeScript 타입의 가장 직접적인 breaking point - schema property를 optional에서 required로 바꾸면 기존 호출자가 더 이상 컴파일되지 않을 수 있다.
- response schema에서 required가 추가되면 서버 응답 계약은 강화되지만, 클라이언트 타입은 더 엄격해져 mock·fixture·테스트 코드가 깨질 수 있다.
- request body나 parameter에서 required가 추가되는 것은 일반적으로 명확한 breaking change다.
-
CI guardrail:
- request parameter/body required 추가 탐지
- 기존 response required 추가도 소비자 영향 분석 대상으로 표시
- 생성 SDK를
tsc --noEmit로 소비자 fixture와 함께 컴파일
-
nullable+oneOf/anyOf조합은 생성기별 해석 차이가 크다 - OpenAPI 3.0의
nullable은 JSON Schema 표준의type: ["null", ...]방식과 다르며, 도구별로 해석 편차가 생기기 쉽다. - TypeScript 생성물에서는
T | null, optional property, union type, discriminator narrowing이 서로 얽힌다. oneOfunion에서 nullable case가 명확하지 않으면 타입은 생성되지만 런타임 데이터와 맞지 않을 수 있다.-
CI guardrail:
- nullable union schema에 fixture 기반 encode/decode 테스트 추가
oneOfvariant별 샘플 response를 생성 SDK 타입에 대입하는 compile test 작성- generator upgrade 시 nullable union 스냅샷 diff 필수 검토
-
discriminator는 문서화용이 아니라 생성기 동작에 영향을 준다 - OpenAPI Generator TypeScript 계열 설정에는 discriminator 처리 방식과 관련된 옵션이 있다.
legacyDiscriminatorBehavior같은 설정은oneOf/anyOf/allOf에서 discriminator mapping 검증과 포함 범위에 영향을 줄 수 있다.- discriminator property가 실제 schema의
required에 포함되지 않으면 타입 narrowing과 런타임 판별이 불안정해진다. -
CI guardrail:
- discriminator property는 각 variant에서
required로 강제 - discriminator
mapping명시 - mapping target schema명 변경 시 generated type diff 검토
- generator config의 discriminator 관련 옵션을 repo에 고정
- discriminator property는 각 variant에서
-
additionalProperties기본값은 TypeScript index signature에 영향을 준다 - OpenAPI Schema Object에서
additionalProperties는 객체가 명시되지 않은 속성을 받을 수 있는지와 관련된다. - OpenAPI Generator TypeScript generator에는
disallowAdditionalPropertiesIfNotPresent같은 옵션이 있으며, 이 값에 따라 명시되지 않은 속성을 허용할지 여부가 달라질 수 있다. - 이 설정이 바뀌면
{ [key: string]: ... }형태의 index signature가 생기거나 사라져 SDK 타입 호환성이 크게 바뀐다. -
CI guardrail:
- generator config에
disallowAdditionalPropertiesIfNotPresent값을 명시적으로 고정 - object schema에는 가능한 한
additionalProperties: false또는 명시적 value schema를 작성 - config 변경은 generated type diff와 함께 리뷰
- generator config에
-
enum확장은 서버-클라이언트 호환성 관점에서 애매하다 - 서버가 새로운 enum 값을 반환하면 기존 TypeScript union type은 이를 모를 수 있다.
- OpenAPI Generator TypeScript 계열에는 알 수 없는 enum 값을 처리하기 위한
enumUnknownDefaultCase옵션이 있다. - 이 옵션을 사용하면 문서에 없는 enum 값에 대해
unknown_default_open_api같은 fallback case를 생성할 수 있다. -
CI guardrail:
- response enum 확장은 “wire-compatible but SDK-impacting”으로 분류
- request enum 축소 또는 값 제거는 breaking으로 분류
- 외부 API 클라이언트라면
enumUnknownDefaultCase사용 검토 - 내부 API라면 enum drift를 contract test로 검출
-
OpenAPI diff만으로는 충분하지 않다
oasdiff나openapi-diff같은 도구는 스펙 간 breaking change 탐지에 유용하다.- 그러나 TypeScript SDK 생성 결과는 generator 버전, template, config option, naming convention에 따라 달라진다.
- 따라서 “spec diff clean”이어도 generated SDK가 breaking일 수 있다.
-
권장 CI workflow:
- OpenAPI lint
- OpenAPI breaking diff
- generator version 확인
- SDK 재생성
- generated files diff 확인
tsc --noEmit- fixture-based type/runtime tests
- published package API diff 또는 소비자 smoke test
-
Generator version pinning은 필수
- OpenAPI Generator는 같은 OpenAPI 문서라도 버전·옵션에 따라 다른 TypeScript 코드를 생성할 수 있다.
- Docker image tag, npm package version, Maven plugin version 등을 고정하지 않으면 CI와 로컬 결과가 어긋날 수 있다.
- CI guardrail:
- generator version lock
- config file commit
- generated output commit 여부를 팀 규칙으로 명시
- generator upgrade PR은 일반 API 변경 PR과 분리
Cautions#
- 이 초안은 공개 문서와 공개 저장소 URL을 기반으로 한 private capsule 초안이다. 개별 프로젝트의 generator 종류가
typescript-fetch,typescript-axios,typescript-node,typescript-angular중 무엇인지에 따라 세부 옵션과 생성 결과가 달라질 수 있다. - OpenAPI Generator의 TypeScript generator 옵션은 generator별로 다르다. 같은 이름의 옵션이라도 기본값이나 적용 범위가 다를 수 있으므로 실제 사용 중인 generator 문서를 확인해야 한다.
nullable과oneOf/anyOf/allOf조합의 실패 모드는 OpenAPI 3.0, OpenAPI 3.1, JSON Schema dialect, generator version에 따라 달라질 수 있다.enumUnknownDefaultCase는 forward compatibility에 도움이 되지만, 도메인상 알 수 없는 enum 값을 허용하면 안 되는 경우에는 오히려 오류를 숨길 수 있다.additionalProperties: false를 일괄 적용하면 타입은 엄격해지지만, 서버가 확장 필드를 추가하는 방식의 API evolution과 충돌할 수 있다.- OpenAPI diff 도구의 breaking-change 판정은 절대적인 법칙이 아니다. 실제 SDK 소비자 코드에서의 compile/test 결과와 함께 판단해야 한다.
- 공개 GitHub issue는 특정 버전·generator·설정에 묶인 사례일 수 있으므로, 그대로 일반화하기보다는 회귀 테스트 케이스로 재현 가능한지 확인해야 한다.
Sources#
- https://spec.openapis.org/oas/v3.0.3.html
- https://openapi-generator.tech/docs/generators/typescript-fetch/
- https://openapi-generator.tech/docs/generators/typescript-axios/
- https://github.com/OpenAPITools/openapi-generator
- https://github.com/OpenAPITools/openapi-diff
- https://github.com/oasdiff/oasdiff
Related#
- Capsule OpenAPI Schema Drift Detection and Repair Pipeline for Generated Clients
- allOf, and Schema Drift Guardrails
- OpenAPI Schema Drift Detection and Breaking-Change Gates for FastAPI Services
Sagwan Revalidation 2026-05-17T13:10:01Z#
- verdict:
ok - note: 핵심 가드레일과 drift 위험 항목은 현재 OpenAPI/TS 실무에도 유효함
Sagwan Revalidation 2026-05-18T13:33:56Z#
- verdict:
ok - note: OpenAPI/TS 생성 drift 가드레일 내용은 현재 practice와도 부합함
Sagwan Revalidation 2026-05-19T14:03:39Z#
- verdict:
ok - note: 전반적 가드레일과 위험 항목이 최신 실무와 여전히 부합함
Sagwan Revalidation 2026-05-20T14:27:00Z#
- verdict:
ok - note: 핵심 위험요소와 CI 가드레일은 현재 실무에도 유효함
Sagwan Revalidation 2026-05-21T15:02:16Z#
- verdict:
ok - note: 핵심 가드레일과 위험 항목이 현재 OpenAPI/TS 실무에도 유효함
Sagwan Revalidation 2026-05-22T15:37:29Z#
- verdict:
ok - note: 전일 검증 이후 관련 표준·도구 관행의 중대한 변화가 없습니다.
Sagwan Revalidation 2026-05-23T16:18:20Z#
- verdict:
ok - note: OpenAPI/TS 생성 클라이언트 drift 가드레일은 현재도 유효함
Sagwan Revalidation 2026-05-24T16:37:58Z#
- verdict:
ok - note: OpenAPI/TS 생성 클라이언트 drift 가드레일로 여전히 유효함
Sagwan Revalidation 2026-05-25T17:03:16Z#
- verdict:
ok - note: 핵심 가드레일과 위험 지점은 현재 OpenAPI/TS 생성 practice와 부합함
Sagwan Revalidation 2026-05-26T17:06:48Z#
- verdict:
ok - note: OpenAPI/TS 생성 클라이언트 가드레일로 여전히 재사용 가능함
Sagwan Revalidation 2026-05-27T17:23:02Z#
- verdict:
ok - note: OpenAPI/TS 생성 drift 가드레일 권장안은 현재도 실무적으로 유효함
Sagwan Revalidation 2026-05-28T18:07:41Z#
- verdict:
ok - note: OpenAPI/TS 생성 클라이언트 drift 가드레일로 여전히 유효함
Sagwan Revalidation 2026-05-29T18:38:27Z#
- verdict:
ok - note: 핵심 가드레일과 위험 항목이 현재 OpenAPI/TS 실무와 여전히 부합함
Sagwan Revalidation 2026-05-30T18:39:30Z#
- verdict:
ok - note: 최근 관행과 핵심 가드레일 모두 여전히 유효합니다.
Sagwan Revalidation 2026-06-01T01:20:49Z#
- verdict:
ok - note: [chatgpt HTTP 401] {
Sagwan Revalidation 2026-06-02T01:32:03Z#
- verdict:
ok - note: OpenAPI 생성 TS 클라이언트 drift 가드레일은 현재도 유효함
Sagwan Revalidation 2026-06-03T02:13:23Z#
- verdict:
ok - note: 핵심 위험 지점과 CI 가드레일이 현재 OpenAPI/TS 실무와 부합함
Sagwan Revalidation 2026-06-04T02:16:33Z#
- verdict:
ok - note: 일반적 가드레일과 drift 실패 모드는 현재 practice와도 부합함
Sagwan Revalidation 2026-06-05T02:43:43Z#
- verdict:
ok - note: CI 가드레일과 drift 실패 모드 설명은 현재도 실무적으로 유효함