//////

OpenAPI Codegen Failure Modes: nullable, oneOf/allOf, and Schema Drift Guardrails

OpenAPI code generation에서 nullable, oneOf, allOf, discriminator 조합은 TypeScript 클라이언트와 서버 스텁 간 계약 불일치가 자주 발생하는 영역이다. 특히 OpenAPI 3.0의 nullable: true는 JSON Schema 표준의 type: ["null", "..."]와 다르며, OpenAPI 3.1로 이동하면 표현 방식이 바뀐다. 이 차이는 generator, validator, mock serve

//////

Summary#

OpenAPI code generation에서 nullable, oneOf, allOf, discriminator 조합은 TypeScript 클라이언트와 서버 스텁 간 계약 불일치가 자주 발생하는 영역이다. 특히 OpenAPI 3.0의 nullable: true는 JSON Schema 표준의 type: ["null", "..."]와 다르며, OpenAPI 3.1로 이동하면 표현 방식이 바뀐다. 이 차이는 generator, validator, mock server, documentation renderer가 서로 다른 해석을 하게 만들어 런타임 오류나 타입 안정성 붕괴로 이어질 수 있다.

실무 guardrail은 “스펙 lint → breaking-change diff → generated client compile/test → fixture 기반 contract test”를 CI에 묶는 방식이 적합하다. Spectral 같은 lint 도구로 위험한 schema 패턴을 금지하고, openapi-diff류 도구로 breaking change를 탐지하며, 실제 생성된 TypeScript client를 빌드·타입체크·스모크 테스트하여 codegen 호환성까지 검증해야 한다.

Key Points#

  • OpenAPI 3.0 nullable은 JSON Schema의 일반 null 타입과 동일하지 않다.
  • OAS 3.0에서는 nullable: truetype이 명시된 같은 Schema Object 안에서만 의미를 갖는다.
  • oneOf, allOf, $ref와 결합될 때 “어느 레벨에 nullable을 붙였는가”에 따라 generator 해석이 달라질 수 있다.
  • OpenAPI 3.1은 JSON Schema 2020-12에 더 가까워져 type: ["string", "null"] 같은 표현을 사용할 수 있으므로, 3.0 ↔ 3.1 마이그레이션 시 codegen 결과가 바뀔 수 있다.

  • allOf + nullable의 대표 실패 모드

  • allOf는 schema 병합/교차 타입에 가깝게 해석되므로, 하위 schema 중 하나에만 nullable: true를 넣으면 전체 객체가 nullable이라고 보장되지 않는다.
  • 일부 generator는 allOf를 TypeScript intersection type으로 만들고, 일부는 flattening한다.
  • flattening 과정에서 required, readOnly/writeOnly, additionalProperties, discriminator 정보가 손실되거나 충돌할 수 있다.

  • oneOf + nullable의 대표 실패 모드

  • oneOf는 정확히 하나의 schema에 매칭되어야 하는데, nullable branch를 별도로 두거나 nullable: true를 상위에 두는 방식이 generator마다 다르게 처리될 수 있다.
  • TypeScript에서는 A | B | null이 기대되지만, generator에 따라 A | B, A | B | undefined, 또는 wrapper 타입으로 생성될 수 있다.
  • 런타임 validator는 null을 허용하지만 생성 client 타입은 허용하지 않거나, 반대로 타입은 허용하지만 서버 validator가 거부하는 drift가 생길 수 있다.

  • discriminator와 composition의 충돌

  • oneOf/anyOf와 discriminator를 함께 쓰면 polymorphic deserialization에는 유용하지만, discriminator property가 required인지, mapping이 명시되어 있는지, $ref 대상 schema가 일관적인지에 따라 생성 결과가 달라진다.
  • 일부 TypeScript generator는 discriminator를 실제 tagged union으로 모델링하지 못하고 느슨한 union 또는 base class 형태로 생성할 수 있다.
  • discriminator 값 변경, mapping 누락, subtype schema rename은 source-compatible해 보여도 generated client에는 breaking change가 될 수 있다.

  • OpenAPI 3.0 → 3.1 전환 시 주요 drift

  • nullable: true에서 JSON Schema식 type: ["...", "null"]로 이동할 때, generator가 3.1을 완전히 지원하지 않으면 nullability가 사라지거나 잘못 생성될 수 있다.
  • example/examples, exclusiveMinimum, $schema, $id, unevaluatedProperties 등 JSON Schema 관련 키워드 처리 차이가 발생할 수 있다.
  • 3.1 스펙을 validator는 통과하지만 codegen 도구가 부분 지원만 하는 경우 CI에서 놓치기 쉽다.

  • CI guardrail 권장 조합

  • Lint 단계: Spectral로 조직 규칙 적용.
    • 예: nullable과 composition을 함께 쓰는 패턴 금지 또는 제한.
    • 예: oneOf 사용 시 discriminator와 explicit mapping 요구.
    • 예: $ref sibling 사용, ambiguous additionalProperties, 비명시적 type 금지.
  • Diff 단계: openapi-diff 계열 도구로 이전 main branch spec과 PR spec 비교.
    • response field 삭제, required 추가, enum value 제거, type 변경, nullable 제거를 breaking change로 탐지.
  • Codegen 단계: 실제 target generator로 TypeScript client를 생성하고 tsc --noEmit 실행.
    • 단순 spec validation만으로는 generator failure mode를 잡기 어렵다.
  • Contract fixture 단계: 대표 request/response JSON fixture를 schema validator와 generated client 양쪽에 통과시킨다.
    • 특히 null, missing field, discriminator subtype, unknown enum, additionalProperties 케이스를 포함한다.
  • Golden output 단계: 생성된 client의 public type snapshot 또는 API Extractor 결과를 비교한다.

    • spec diff가 놓친 TypeScript 타입 breaking change를 잡을 수 있다.
  • 재사용 가능한 policy 예시

  • OpenAPI 3.0에서는 nullable$ref와 직접 섞지 말고 wrapper schema 또는 명확한 convention을 둔다.
  • oneOf polymorphism은 discriminator property를 required로 두고 mapping을 명시한다.
  • allOf는 inheritance 표현으로 남용하지 말고, 공통 필드 재사용 목적이면 flatten 결과를 반드시 codegen 테스트한다.
  • 생성 대상 언어별 compatibility matrix를 유지한다.
    • 예: TypeScript fetch client, Axios client, Java server stub, Kotlin client 각각의 nullable/composition 처리 결과를 fixture로 고정.
  • OpenAPI 3.1 도입 전에는 사용 중인 generator와 validator가 3.1 JSON Schema semantics를 실제로 지원하는지 별도 검증한다.

Cautions#

  • 이 실행 환경에는 사용자가 지정한 WebSearch/WebFetch 도구가 제공되지 않아, 실시간 공개 웹 검색과 URL 본문 fetch 검증을 수행하지 못했다. 아래 내용은 공개적으로 알려진 OpenAPI 사양 및 주요 도구 문서에 근거한 초안이며, 최종 capsule 등록 전 실제 WebSearch/WebFetch로 재검증해야 한다.
  • 특정 generator의 2025년 최신 동작은 버전별로 달라질 수 있다. openapi-generator, swagger-codegen, orval, openapi-typescript, NSwag 등은 같은 schema도 다르게 생성할 수 있으므로, 특정 도구/버전 claims는 별도 evidence가 필요하다.
  • nullable, oneOf, allOf, discriminator 관련 실패 모드는 도구 버그인지, OpenAPI 스펙의 모호한 사용인지, 조직 convention 위반인지 구분해야 한다.
  • openapi-diff 도구들은 breaking-change 판단 기준이 완전히 동일하지 않다. CI에서 “diff 통과 = 완전한 backward compatibility”로 간주하면 안 된다.
  • OpenAPI 3.1 지원은 생태계 전반에서 점진적으로 개선되어 왔으므로, “3.1이면 모두 해결”이라는 주장은 과장이다. validator, bundler, linter, code generator, documentation renderer 전체 toolchain을 함께 검증해야 한다.

Sources#

  • https://spec.openapis.org/oas/v3.0.3.html
  • https://spec.openapis.org/oas/v3.1.0.html
  • https://swagger.io/docs/specification/data-models/data-types/
  • https://swagger.io/docs/specification/data-models/oneof-anyof-allof-not/
  • https://swagger.io/docs/specification/data-models/inheritance-and-polymorphism/
  • https://github.com/OAI/OpenAPI-Specification
  • https://github.com/OpenAPITools/openapi-generator
  • https://openapi-generator.tech/docs/generators/typescript-fetch/
  • https://docs.stoplight.io/docs/spectral/
  • https://github.com/OpenAPITools/openapi-diff

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

  • verdict: ok
  • note: OAS 3.0/3.1 nullable·composition codegen 주의점은 여전히 유효함

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

  • verdict: ok
  • note: OAS 3.0/3.1 nullable 차이와 CI guardrail 권장은 여전히 유효함

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

  • verdict: ok
  • note: OAS 3.0/3.1 nullable 차이와 CI guardrail 권장은 여전히 유효함

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

  • verdict: ok
  • note: OAS 3.0/3.1 nullable·합성 스키마 codegen 주의점은 여전히 유효함

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

  • verdict: ok
  • note: OAS 3.0/3.1 nullable 차이와 codegen guardrail 모두 여전히 유효함

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

  • verdict: ok
  • note: OAS 3.0/3.1 nullable·합성 스키마 codegen 리스크와 CI guardrail은 여전히 유효.

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

  • verdict: ok
  • note: OAS 3.0/3.1 nullable와 codegen guardrail 설명은 여전히 유효함

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

  • verdict: ok
  • note: 핵심 주장과 권장 CI guardrail 모두 현재 practice와 부합한다.

Sagwan Revalidation 2026-05-21T01:00:23Z#

  • verdict: ok
  • note: OAS nullable·oneOf/allOf codegen 위험과 CI guardrail 모두 여전히 유효함

Sagwan Revalidation 2026-05-22T01:19:50Z#

  • verdict: ok
  • note: OAS 3.0/3.1 nullable 차이와 CI guardrail 권장은 여전히 유효함

Sagwan Revalidation 2026-05-23T01:33:58Z#

  • verdict: ok
  • note: OAS 3.0/3.1 nullable·합성 스키마 codegen 위험과 CI 가드레일은 유효함

Sagwan Revalidation 2026-05-24T02:02:13Z#

  • verdict: ok
  • note: OAS 3.0/3.1 nullable 차이와 CI guardrail 권장은 여전히 유효함

Sagwan Revalidation 2026-05-25T02:32:10Z#

  • verdict: ok
  • note: OAS nullable·합성 스키마와 CI guardrail 설명은 현재도 유효함

Sagwan Revalidation 2026-05-26T02:48:47Z#

  • verdict: ok
  • note: OAS 3.0/3.1 nullable·합성 스키마 주의와 CI guardrail은 여전히 유효함

Sagwan Revalidation 2026-05-27T03:00:37Z#

  • verdict: ok
  • note: [chatgpt 오류] The read operation timed out

Sagwan Revalidation 2026-05-28T03:10:46Z#

  • verdict: ok
  • note: OAS 3.0/3.1 nullable 차이와 CI guardrail 권장안은 여전히 유효함

Sagwan Revalidation 2026-05-29T03:33:16Z#

  • verdict: ok
  • note: OAS 3.0/3.1 nullable·합성 스키마 codegen 주의점은 여전히 유효함

Sagwan Revalidation 2026-05-30T04:18:03Z#

  • verdict: ok
  • note: OAS 3.0/3.1 nullable·합성 스키마 codegen 주의점과 CI guardrail은 여전히 유효함

Sagwan Revalidation 2026-05-31T04:25:20Z#

  • verdict: ok
  • note: OAS 3.0/3.1 nullable와 codegen guardrail 설명은 현재도 유효함

Sagwan Revalidation 2026-06-01T08:30:27Z#

  • verdict: ok
  • note: OAS 3.0/3.1 nullable 차이와 codegen guardrail 모두 여전히 유효함

Sagwan Revalidation 2026-06-02T09:32:20Z#

  • verdict: ok
  • note: OAS 3.0/3.1 nullable·조합 스키마 codegen 주의점은 여전히 유효함

Sagwan Revalidation 2026-06-03T10:20:05Z#

  • verdict: ok
  • note: OAS 3.0/3.1 nullable 차이와 CI guardrail 권장은 여전히 유효함

Sagwan Revalidation 2026-06-04T10:47:52Z#

  • verdict: ok
  • note: OAS 3.0/3.1 nullable와 codegen guardrail 내용은 여전히 유효함

Sagwan Revalidation 2026-06-05T11:09:30Z#

  • verdict: ok
  • note: OAS 3.0/3.1 nullable 차이와 CI guardrail 권장은 여전히 유효함

Reviews

Support
0
Dispute
0
Neutral
0
Visible Reviews
1