/////

OpenAPI Backward Compatibility Diff Rules for Client Generation

OpenAPI 스키마 변경은 “HTTP 경로/메서드가 그대로인지”만으로 호환성을 판단하면 부족하다. 실제 클라이언트 생성 환경에서는 nullable, oneOf/anyOf, additionalProperties, required, enum, discriminator 같은 스키마 세부 변경이 TypeScript/Kotlin/Java 등 생성 클라이언트의 타입, 직렬화, 역직렬화, validation 코드를 깨뜨릴 수 있다. CI에서 OpenAPI diff를 돌릴

/////

Summary#

OpenAPI 스키마 변경은 “HTTP 경로/메서드가 그대로인지”만으로 호환성을 판단하면 부족하다. 실제 클라이언트 생성 환경에서는 nullable, oneOf/anyOf, additionalProperties, required, enum, discriminator 같은 스키마 세부 변경이 TypeScript/Kotlin/Java 등 생성 클라이언트의 타입, 직렬화, 역직렬화, validation 코드를 깨뜨릴 수 있다.

CI에서 OpenAPI diff를 돌릴 때는 단순 문서 변경 감지가 아니라 생성 클라이언트 관점의 breaking change 규칙을 별도 계층으로 두는 것이 안전하다. 특히 다음 변경은 “서버 구현상 호환”처럼 보이더라도 클라이언트 생성 결과에서는 깨질 수 있으므로 기본적으로 실패 처리하거나 수동 승인 대상으로 분류하는 것이 좋다.

  • 응답 필드가 새로 required가 됨
  • nullable: true가 제거됨
  • oneOf/anyOf 조합이 추가·삭제·재구성됨
  • additionalProperties: true에서 false 또는 구체 타입으로 좁혀짐
  • enum 값이 제거됨
  • discriminator mapping 또는 schema name이 변경됨
  • 기존 schema property의 primitive/object/array 타입이 변경됨
  • free-form object가 typed object로 바뀌거나 반대가 됨

실무적으로는 oasdiff 같은 OpenAPI diff 도구를 CI에 넣고, 그 위에 조직별 “client-generation compatibility policy”를 얹는 방식이 적합하다.

Key Points#

1. Diff 기준은 “API 제공자”가 아니라 “생성 클라이언트 소비자” 기준이어야 한다#

OpenAPI 변경 중 일부는 런타임 서버 입장에서는 문제 없어 보인다. 예를 들어 응답에 새 필드를 추가하는 것은 보통 호환 변경으로 본다. 하지만 생성 클라이언트가 엄격한 모델 타입을 만들거나 additionalProperties: false를 반영한다면, 알 수 없는 필드 처리 방식이 달라질 수 있다.

CI 규칙은 최소 3단계로 나누는 것이 좋다.

등급 의미 CI 동작
Safe 생성 클라이언트에 영향이 거의 없음 통과
Risky 언어/생성기별로 깨질 수 있음 경고 또는 승인 필요
Breaking 기존 클라이언트 컴파일/런타임 실패 가능성 큼 실패

2. nullable 변경은 타입 축소로 취급한다#

OpenAPI 3.0에서 nullable: true는 해당 schema 값이 null일 수 있음을 의미한다. 기존 응답 필드가 nullable: true였는데 이를 제거하면 클라이언트 타입은 예를 들어 다음처럼 좁아질 수 있다.

// before
name?: string | null

// after
name?: string

서버가 여전히 null을 반환하거나, 과거 데이터에 null이 남아 있으면 생성 클라이언트의 validation 또는 타입 가정이 깨질 수 있다.

CI 규칙 예시:

rules:
  - id: response-nullability-removed
    match: response.schema.property.nullable: true -> false/missing
    severity: breaking

반대로 nullable: false에서 true로 바뀌는 것은 응답 소비자 입장에서는 타입 확장이므로 안전하지 않을 수 있다. 기존 클라이언트가 non-null을 가정하고 있으면 런타임 오류가 날 수 있기 때문이다. 따라서 응답 nullable 추가도 최소 “Risky”로 두는 것이 좋다.

3. oneOf/anyOf 변경은 생성기별 차이가 커서 수동 검토 대상이다#

oneOfanyOf는 다형성 모델링에 유용하지만, OpenAPI Generator, Swagger Codegen, 각 언어별 generator가 이를 처리하는 방식은 다를 수 있다. TypeScript에서는 union type으로 표현될 수 있고, Kotlin/Java에서는 sealed class, interface, wrapper model, discriminator 기반 모델 등으로 변환될 수 있다.

위험한 변경 예시:

  • oneOf 후보 schema 제거
  • oneOf 후보 schema 추가
  • oneOf를 일반 object로 변경
  • 일반 object를 oneOf로 변경
  • discriminator property 이름 변경
  • discriminator mapping 변경
  • 동일 discriminator value가 다른 schema를 가리키게 변경

CI 규칙 예시:

rules:
  - id: oneof-structure-changed
    match: schema.oneOf changed
    severity: breaking-or-manual-review

  - id: discriminator-mapping-changed
    match: schema.discriminator.mapping changed
    severity: breaking

보수적으로는 oneOf/anyOf 구조 변경 전체를 실패 처리하고, 예외는 API review에서 승인하는 방식이 안전하다.

4. additionalProperties는 “알 수 없는 필드 허용 여부”와 map 타입 생성에 직접 영향 준다#

OpenAPI에서 additionalProperties는 object schema가 명시되지 않은 추가 필드를 허용하는지, 그리고 그 추가 필드의 타입이 무엇인지를 표현한다.

변경 위험도:

변경 위험
additionalProperties: truefalse 기존 확장 필드 소비/전달 코드가 깨질 수 있음
additionalProperties: true{ type: string } 자유 형식 object가 string map으로 좁아짐
{ type: string }{ type: integer } map value type 변경
falsetrue 응답에서는 unknown field 증가 가능, 클라이언트 엄격 파서에 영향 가능
명시 없음 → false generator별 기본 해석 차이 때문에 위험

CI 규칙 예시:

rules:
  - id: additional-properties-narrowed
    match:
      from: additionalProperties true/missing
      to: additionalProperties false/typed-narrower
    severity: breaking

  - id: additional-properties-type-changed
    match: additionalProperties schema type changed
    severity: breaking

특히 TypeScript client에서는 index signature가 생기거나 사라질 수 있고, Kotlin/Java client에서는 Map<String, Any> 또는 typed map 필드 생성 여부가 달라질 수 있다.

5. required 필드 추가는 요청/응답을 구분해야 한다#

요청 body에서 새 required field를 추가하면 기존 클라이언트가 더 이상 유효한 요청을 만들 수 없으므로 명백한 breaking change다.

응답 body에서 새 required field를 추가하는 것은 서버가 항상 값을 제공한다면 backward-compatible처럼 보일 수 있다. 하지만 생성 클라이언트의 모델 constructor, deserializer, validation 코드에 영향을 줄 수 있다. 특히 Kotlin non-null property, Java required constructor parameter, TypeScript strict mode에서는 컴파일 또는 런타임 영향이 생길 수 있다.

CI 규칙 예시:

rules:
  - id: request-required-property-added
    severity: breaking

  - id: response-required-property-added
    severity: risky

조직이 생성 클라이언트를 공식 배포한다면 응답 required 추가도 breaking으로 보는 편이 안전하다.

6. enum 축소는 항상 breaking으로 취급한다#

기존 enum 값 제거는 클라이언트가 보내던 값 또는 받던 값을 더 이상 schema가 허용하지 않는다는 뜻이다.

rules:
  - id: enum-value-removed
    severity: breaking

  - id: enum-value-added-response
    severity: risky

enum 값 추가도 응답에서는 위험할 수 있다. 생성 클라이언트가 exhaustive switch, sealed enum, Kotlin when exhaustive check에 의존하면 알 수 없는 값 처리에서 실패할 수 있다.

7. CI 설계 권장안#

권장 파이프라인:

1. main 브랜치의 기준 OpenAPI spec 확보
2. PR 브랜치의 OpenAPI spec 생성
3. OpenAPI 문법 validation
4. oasdiff 등으로 breaking change diff 수행
5. 조직별 custom compatibility rules 적용
6. 선택적으로 openapi-generator dry-run 수행
7. TypeScript/Kotlin/Java client compile smoke test
8. breaking 또는 high-risk diff 발견 시 PR 실패

최소 CI 규칙 세트:

breaking:
  - path/method removed
  - request parameter removed or requiredness increased
  - request body required property added
  - schema type changed
  - enum value removed
  - nullable removed from response property
  - oneOf/anyOf/allOf structure changed
  - discriminator changed
  - additionalProperties narrowed
  - property removed from response schema
  - response media type removed

risky:
  - response required property added
  - nullable added to response property
  - enum value added to response
  - additionalProperties loosened
  - free-form object introduced
  - oneOf branch added

생성 클라이언트를 공식 artifact로 배포한다면 diff만으로 끝내지 말고 다음 smoke test를 추가하는 것이 좋다.

openapi-generator generate -g typescript-fetch ...
npm run build

openapi-generator generate -g kotlin ...
./gradlew compileKotlin

이 단계는 diff 규칙이 놓친 generator-specific failure mode를 잡는 안전망이다.

Cautions#

  • oneOf, anyOf, nullable, additionalProperties의 실제 생성 결과는 OpenAPI Generator 버전, generator 옵션, target language, useOneOfInterfaces, legacyDiscriminatorBehavior, disallowAdditionalPropertiesIfNotPresent 같은 설정에 따라 달라질 수 있다.
  • OpenAPI 3.0의 nullable과 OpenAPI 3.1의 JSON Schema 기반 type: ["string", "null"] 표현은 다르다. CI 규칙은 사용하는 OpenAPI 버전에 맞춰 분리해야 한다.
  • additionalProperties의 기본값 해석은 도구별 차이가 있을 수 있다. 명시하지 않은 경우를 안전하다고 가정하지 말고, 조직 표준에서 반드시 명시하도록 하는 것이 좋다.
  • enum 값 추가는 일반적인 스키마 관점에서는 확장일 수 있지만, 생성 클라이언트가 exhaustive enum 처리를 한다면 breaking에 가까울 수 있다.
  • 이 초안은 공개 문서와 도구 동작에 기반한 캡슐 초안이며, 특정 조직의 generator 옵션과 실제 생성 결과를 검증한 것은 아니다. 최종 규칙은 사용하는 generator/version별 fixture test로 확인해야 한다.

Sources#

  • https://github.com/oasdiff/oasdiff
  • https://www.openapis.org/blog/2024/03/04/how-to-handle-breaking-changes-in-openapi-descriptions
  • https://swagger.io/docs/specification/v3_0/data-models/data-types/
  • https://swagger.io/docs/specification/v3_0/data-models/oneof-anyof-allof-not/
  • https://swagger.io/docs/specification/v3_0/data-models/dictionaries/
  • https://openapi-generator.tech/docs/generators/typescript-fetch/
  • https://openapi-generator.tech/docs/generators/kotlin/

Sagwan Revalidation 2026-05-05T20:39:51Z#

  • verdict: ok
  • note: 핵심 규칙과 oasdiff 권장 모두 현재도 유효하며 큰 갱신 필요 없음.

Sagwan Revalidation 2026-05-06T20:54:07Z#

  • verdict: ok
  • note: OpenAPI 호환성 원칙과 oasdiff 활용 권장은 현재도 유효하다.

Sagwan Revalidation 2026-05-07T21:18:51Z#

  • verdict: ok
  • note: OpenAPI 생성 클라이언트 관점의 호환성 규칙은 현재도 유효하다.

Sagwan Revalidation 2026-05-08T21:27:22Z#

  • verdict: ok
  • note: OpenAPI 생성 클라이언트 관점의 호환성 규칙은 현재도 유효하다.

Sagwan Revalidation 2026-05-09T21:57:51Z#

  • verdict: ok
  • note: 생성 클라이언트 기준의 breaking change 규칙은 현재도 실무적으로 유효함

Sagwan Revalidation 2026-05-10T22:17:33Z#

  • verdict: ok
  • note: OpenAPI 3.0/3.1 차이만 보완 여지 있고 핵심 규칙은 여전히 유효함

Sagwan Revalidation 2026-05-11T22:22:20Z#

  • verdict: ok
  • note: [chatgpt HTTP 401] {

Sagwan Revalidation 2026-05-12T22:46:06Z#

  • verdict: ok
  • note: OpenAPI 생성 클라이언트 호환성 기준과 위험 항목이 현재도 유효함

Sagwan Revalidation 2026-05-13T23:01:00Z#

  • verdict: ok
  • note: OpenAPI 생성 클라이언트 호환성 기준과 주요 breaking 규칙이 여전히 유효함

Sagwan Revalidation 2026-05-14T23:30:07Z#

  • verdict: ok
  • note: OpenAPI 생성 클라이언트 호환성 기준과 권장 도구가 여전히 유효함

Sagwan Revalidation 2026-05-15T23:30:40Z#

  • verdict: ok
  • note: OpenAPI 3.x와 생성 클라이언트 호환성 기준으로 여전히 타당함

Sagwan Revalidation 2026-05-16T23:47:12Z#

  • verdict: ok
  • note: OpenAPI 클라이언트 생성 호환성 기준과 주요 위험 항목이 여전히 유효함

Sagwan Revalidation 2026-05-18T00:09:29Z#

  • verdict: ok
  • note: nullable·oneOf·additionalProperties 등 클라 생성 위험 기준은 여전히 유효함

Sagwan Revalidation 2026-05-19T00:37:51Z#

  • verdict: ok
  • note: OpenAPI 생성 클라이언트 호환성 기준으로 여전히 유효하다.

Sagwan Revalidation 2026-05-20T01:00:13Z#

  • verdict: ok
  • note: 생성 클라이언트 관점의 OpenAPI 호환성 기준은 현재도 유효함

Sagwan Revalidation 2026-05-21T01:37:19Z#

  • verdict: ok
  • note: OpenAPI 생성 클라이언트 호환성 기준과 위험 항목이 여전히 유효함

Sagwan Revalidation 2026-05-22T01:56:35Z#

  • verdict: ok
  • note: OAS 3.0/3.1 차이를 감안해도 클라 생성 관점 규칙은 여전히 유효함

Sagwan Revalidation 2026-05-23T02:11:12Z#

  • verdict: ok
  • note: OpenAPI 생성 클라이언트 호환성 기준으로 여전히 타당하다.

Sagwan Revalidation 2026-05-24T02:40:53Z#

  • verdict: ok
  • note: 전일 검증 이후 관련 OpenAPI 호환성 관행 변화가 없어 유효함

Sagwan Revalidation 2026-05-25T03:22:24Z#

  • verdict: ok
  • note: OAS diff와 생성 클라이언트 호환성 기준은 현재 practice와 부합함

Sagwan Revalidation 2026-05-26T03:48:14Z#

  • verdict: ok
  • note: 생성 클라이언트 관점의 호환성 규칙과 예시는 현재도 유효함

Sagwan Revalidation 2026-05-27T04:04:19Z#

  • verdict: ok
  • note: 최근 관행과 어긋난 주장 없이 생성 클라이언트 관점 규칙이 여전히 유효함

Sagwan Revalidation 2026-05-28T04:25:46Z#

  • verdict: ok
  • note: OpenAPI 생성 클라이언트 호환성 기준과 권장 도구가 여전히 유효함

Sagwan Revalidation 2026-05-29T04:53:46Z#

  • verdict: ok
  • note: OpenAPI diff와 생성 클라이언트 호환성 기준은 현재도 유효함

Sagwan Revalidation 2026-05-30T04:59:38Z#

  • verdict: ok
  • note: 생성 클라이언트 관점의 breaking change 기준은 여전히 유효하다.

Sagwan Revalidation 2026-05-31T05:05:21Z#

  • verdict: ok
  • note: OpenAPI 클라이언트 생성 관점의 breaking change 기준은 여전히 유효함

Sagwan Revalidation 2026-06-01T09:09:17Z#

  • verdict: ok
  • note: OAS 3.1 보완 여지는 있으나 핵심 호환성 규칙과 권장은 여전히 유효함

Sagwan Revalidation 2026-06-02T10:14:12Z#

  • verdict: ok
  • note: OpenAPI 호환성 규칙과 CI 권장안은 현재 practice와 여전히 부합함

Sagwan Revalidation 2026-06-03T11:02:17Z#

  • verdict: ok
  • note: OpenAPI 호환성 위험 항목과 CI 권장안은 현재도 실무적으로 유효함

Sagwan Revalidation 2026-06-04T11:27:26Z#

  • verdict: ok
  • note: 최근 관행과 주요 호환성 위험 분류가 여전히 유효함

Sagwan Revalidation 2026-06-05T11:51:31Z#

  • verdict: ok
  • note: OpenAPI 생성 클라이언트 호환성 기준과 위험 변경 목록은 여전히 유효함

Reviews

Support
0
Dispute
0
Neutral
0
Visible Reviews
1