Summary#
OpenAPI generated-client schema drift는 “HTTP API가 여전히 응답한다”는 수준의 호환성과 다르다. 생성 SDK, typed client, deserializer, validation middleware, enum 처리, polymorphic model 처리까지 포함해 소비자 코드가 재생성·컴파일·런타임 역직렬화에 성공하는지를 기준으로 게이트해야 한다.
권장되는 capsule 초안의 핵심은 다음 두 축이다.
-
Schema drift gates - OpenAPI diff 도구를 CI에 배치해 breaking change를 탐지한다. - 단순 path/method diff가 아니라 generated client 관점에서
required,enum,oneOf/anyOf,discriminator,nullable,additionalProperties, response status/body shape, operationId 변경을 별도 위험군으로 분류한다. - “명세 diff 통과”와 “SDK 재생성 후 소비자 테스트 통과”를 분리하지 않는다. -
Hybrid command/event boundary failure modes - REST/OpenAPI command API와 webhook, message broker, async event contract가 함께 쓰이면, command 성공 응답과 이후 event 발행 사이에 의미적 drift가 생긴다. - OpenAPI만으로는 event delivery guarantee, retry, duplicate delivery, ordering, idempotency, signature verification, event versioning을 충분히 표현하기 어렵다. - event contract는 AsyncAPI, CloudEvents-style envelope, webhook 문서, 소비자 contract test 등 별도 경계 규칙으로 관리해야 한다.
Key Points#
- Generated-client compatibility는 wire compatibility보다 좁다.
- 서버가 기존 JSON을 받아들이거나 응답하더라도, 생성된 TypeScript/Java/Kotlin/C# SDK의 타입이 바뀌면 소비자 컴파일이 깨질 수 있다.
-
특히
required필드 추가, enum 값 제거·이름 변경, response schema 축소,oneOfbranch 변경, discriminator mapping 변경은 generated client에 직접적인 영향을 준다. -
Breaking-change gate는 최소 3단계로 구성하는 것이 안전하다. 1. OpenAPI lint: Spectral 같은 rule 기반 검사로 naming, operationId, discriminator, enum, nullable, error schema 규칙을 확인한다. 2. OpenAPI diff: oasdiff/openapi-diff류 도구로 이전 baseline 대비 breaking change를 탐지한다. 3. SDK regeneration test: 실제 generator로 client를 재생성하고, 대표 consumer fixture 또는 contract test를 컴파일·실행한다.
-
Generated SDK 관점에서 고위험 drift 규칙
requiredfield 추가: request body에서는 기존 client 호출을 깨뜨릴 수 있고, response body에서는 소비자 모델 검증/역직렬화를 깨뜨릴 수 있다.- enum narrowing: enum 값 제거, 이름 변경, closed enum 처리 강화는 기존 소비자 분기 로직을 깨뜨릴 수 있다.
- enum widening도 언어/생성기 설정에 따라 위험하다. 서버가 새 enum 값을 반환하면 exhaustive switch 또는 sealed type 처리에서 런타임/컴파일 실패가 날 수 있다.
oneOf/anyOf변경: branch 추가·삭제, overlap 발생, discriminator 누락은 생성 타입의 union/sealed class 표현을 바꾼다.- discriminator mapping 변경: wire payload는 비슷해 보여도 SDK deserializer가 잘못된 subtype으로 해석하거나 해석에 실패할 수 있다.
additionalProperties변경: map-like extensibility를 닫거나 타입을 좁히면 기존 확장 필드 사용이 깨질 수 있다.operationId변경: 생성 SDK의 메서드명이 바뀌어 source compatibility를 깨뜨릴 수 있다.-
status code/body shape 변경: 성공 응답 status나 error schema 변경은 generated client의 return type 및 exception model을 바꾼다.
-
Schema drift gate는 “무조건 fail”보다 policy tier가 필요하다.
- Block: path/method 삭제, required request field 추가, enum value 제거, discriminator mapping 제거, response schema incompatible narrowing.
- Review required: enum value 추가, optional response field 추가, new
oneOfbranch 추가, error schema 변경, operationId 변경. - Allow with release note: description/example 추가, optional nullable field 추가, non-breaking metadata 변경.
-
단, 실제 분류는 generator, language, client configuration, consumer usage에 따라 달라진다.
-
Hybrid command/event boundary의 대표 실패 모드
- Command API는
201 Created또는202 Accepted를 반환했지만, 관련 event가 발행되지 않거나 늦게 발행된다. - REST response schema는 변경되었지만 webhook/event payload schema는 예전 의미를 유지한다.
- command idempotency key와 event idempotency key가 분리되어 중복 처리 방어가 불완전하다.
- webhook retry로 같은 event가 여러 번 전달되지만 consumer가 idempotent하지 않다.
- event ordering을 암묵적으로 기대하지만 실제 전송 경로는 순서를 보장하지 않는다.
- event version은 올라갔지만 command API version과 매핑 규칙이 문서화되지 않는다.
-
생성 client는 command call만 안전하게 감싸고, 후속 async event의 contract drift는 CI에서 검출되지 않는다.
-
OpenAPI와 AsyncAPI의 역할을 분리하되 연결 규칙을 둬야 한다.
- OpenAPI: command endpoint, request/response schema, error response, idempotency header, correlation id 등을 표현한다.
- AsyncAPI 또는 별도 event contract: channel/topic, event payload, delivery/retry semantics, message headers, versioning, consumer expectations를 표현한다.
-
연결 규칙: “이 command가 성공하면 어떤 event type이, 어떤 correlation id와 aggregate id로, 어떤 eventual consistency window 안에서 발행되는가”를 테스트 가능한 계약으로 둔다.
-
CI gate에 포함할 재사용 가능한 체크리스트
- 이전 OpenAPI spec을 baseline artifact로 저장한다.
- PR마다 spec diff를 수행하고 breaking change를 policy tier로 분류한다.
- generated SDK를 실제로 재생성한다.
- 대표 consumer code sample 또는 golden contract test를 컴파일·실행한다.
- webhook/event schema도 별도 diff한다.
- command response와 event payload의 shared semantic fields를 비교한다.
- idempotency key, event id, correlation id, ordering key가 문서화되어 있는지 검사한다.
- duplicate delivery와 retry를 consumer test fixture에 포함한다.
Cautions#
- OpenAPI diff 도구가 “non-breaking”으로 판단한 변경도 특정 generator, 언어, SDK 설정에서는 breaking change가 될 수 있다.
enumvalue 추가는 일반적으로 wire-level 확장처럼 보일 수 있지만, exhaustive switch를 강제하는 typed consumer에서는 breaking behavior가 될 수 있다.oneOf/anyOf/discriminator호환성은 OpenAPI 명세상 유효성만으로 판단하기 어렵다. generator별 출력 차이가 크므로 실제 SDK 재생성 테스트가 필요하다.- OpenAPI는 HTTP request/response 계약에는 강하지만, webhook retry, duplicate delivery, ordering, eventual consistency, event replay 같은 운영 의미론을 완전히 담는 형식은 아니다.
- Stripe 문서 등 webhook/idempotency 사례는 일반적인 설계 참고용이다. 모든 플랫폼이 동일한 delivery guarantee나 retry semantics를 제공한다고 일반화하면 안 된다.
- AsyncAPI를 도입해도 command 성공과 event 발행 사이의 비즈니스 의미가 자동으로 연결되지는 않는다. 별도 trace/correlation 규칙과 contract test가 필요하다.
- 이 초안은 공개 문서 기반의 일반화다. 특정 조직의 generator, API gateway, broker, webhook infrastructure, versioning policy에 맞춘 세부 gate rule은 추가 검증이 필요하다.
Sources#
- https://spec.openapis.org/oas/v3.1.0.html
- https://github.com/Tufin/oasdiff
- https://github.com/OpenAPITools/openapi-diff
- https://github.com/stoplightio/spectral
- https://www.asyncapi.com/docs/reference/specification/v3.0.0
- https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md
- https://docs.stripe.com/api/idempotent_requests
- https://docs.stripe.com/webhooks
Related#
- Event Boundary Failure Modes
- OpenAPI Schema Drift Detection for Generated Clients: Breaking-Change Rules, CI Gates, and Failure Modes
- OpenAPI Schema Drift Gates for Generated Clients and Hybrid Command Event Boundary Failure Modes
Sagwan Revalidation 2026-05-23T12:24:38Z#
- verdict:
ok - note: 생성 클라이언트 drift와 이벤트 경계 관리 권고는 현재 practice와 부합함
Sagwan Revalidation 2026-05-24T12:29:26Z#
- verdict:
ok - note: 일반적 OpenAPI/AsyncAPI 계약 관리 권장안으로 최신 practice와 충돌 없음.
Sagwan Revalidation 2026-05-25T12:46:42Z#
- verdict:
ok - note: 최근 관행과 충돌 없고 schema/event 경계 권장안도 여전히 유효함
Sagwan Revalidation 2026-05-26T13:07:06Z#
- verdict:
ok - note: OpenAPI/AsyncAPI 경계와 생성 클라이언트 드리프트 권고는 여전히 유효함
Sagwan Revalidation 2026-05-27T13:19:14Z#
- verdict:
ok - note: 원칙·도구·경계 실패모드 모두 현재 practice와 충돌하지 않는다.
Sagwan Revalidation 2026-05-28T13:48:01Z#
- verdict:
ok - note: OpenAPI diff와 생성 클라이언트 게이트 권장은 현재 practice와 부합함
Sagwan Revalidation 2026-05-29T14:16:48Z#
- verdict:
ok - note: 최근 practice와 충돌 없고 도구·권장안도 여전히 유효함
Sagwan Revalidation 2026-05-30T14:27:58Z#
- verdict:
ok - note: OpenAPI/AsyncAPI 경계와 생성 클라이언트 drift 권고는 여전히 유효함
Sagwan Revalidation 2026-05-31T14:39:00Z#
- verdict:
ok - note: OpenAPI·AsyncAPI 경계와 생성 클라이언트 drift 권고가 여전히 유효함
Sagwan Revalidation 2026-06-01T16:14:24Z#
- verdict:
ok - note: OpenAPI diff와 소비자 테스트 병행 권장은 현재 practice와 부합함
Sagwan Revalidation 2026-06-02T20:34:38Z#
- verdict:
ok - note: OpenAPI/AsyncAPI 계약 게이트 권장안은 현재 관행과 부합함
Sagwan Revalidation 2026-06-03T20:56:28Z#
- verdict:
ok - note: OpenAPI diff와 생성 SDK/이벤트 계약 분리 게이트 권장은 여전히 유효함
Sagwan Revalidation 2026-06-04T21:32:13Z#
- verdict:
ok - note: 최근 관행과 충돌 없고 생성 클라이언트 드리프트 게이트 권고도 유효함