Skip to content

OpenAPI 3.0 / 3.1 Compatibility

Soxom accepts both OpenAPI 3.0 and 3.1 specs and ships six generators: Python, Java, Go, TypeScript, Ruby, and C#.

Go, TypeScript, and Python are at near-full coverage of both versions. Java and Ruby are close behind — Java models the full operation / parameter / auth / content-type surface plus Bean Validation constraints, and Ruby covers the same breadth minus a few schema-level validation keywords. C# is the newest generator: it covers most of the surface (all auth schemes, every parameter style, multipart / octet bodies, discriminated unions) but does not yet model document-level servers, response headers, status-code ranges, tags, or x-* extensions.

When a generator encounters a keyword it cannot fully model in the target language, it does not fail the build (with one exception — see the note on C# below). Instead it:

  1. Emits a diagnostic line to the build log naming the feature and the JSON pointer where it appeared.
  2. Falls back to the language’s untyped escape hatch (any, Object, interface{}, JsonElement, …) so the rest of the SDK still generates.

Diagnostic conventions differ by generator:

  • Python, Java, Go, TypeScript emit the uniform [soxom:warn] unsupported OpenAPI feature '<name>' at <pointer> line.
  • C# emits coded diagnostics (SOX004, SOX005, SOX006, …) at info / warning level instead of the [soxom:warn] prefix, and its parser (Microsoft.OpenApi) is strict — a spec with an invalid enum value (e.g. a bogus parameter style) is rejected outright rather than warned-and-degraded.
  • Ruby does not emit a per-feature warning line; schema keywords it cannot model are accepted silently (the generated type still builds, the constraint is simply not enforced). A run-level summary is printed to stderr.

Use the matrix below to see what to expect per generator.

  • ✅   Full — the feature shapes the generated code.
  • ⚠️   Degraded — recognised; falls back to any / Object / interface{} / JsonElement (and warns, except in Ruby).
  • ❌   Silently dropped — not modelled; the field/keyword is omitted with no diagnostic.
Feature3.0 form3.1 formPythonJavaGoTypeScriptRubyC#
Nullable typenullable: truetype: ["string", "null"]
examples (array)example (single)examples: [...]
Exclusive boundsexclusiveMaximum: true + maximumexclusiveMaximum: 100
String constraints (pattern, minLength, maxLength)samesame
Numeric constraints (minimum, maximum, multipleOf)samesame⚠️ Ⓡ
Array constraints (minItems, maxItems, uniqueItems)samesame
Object constraints (minProperties, maxProperties)samesame
default valuessamesame
readOnly / writeOnlysamesame
deprecated (schema / operation / parameter)samesame
Typed formats (uuid, email, uri, ipv4, ipv6, byte, int32)samesame
constconst: "v1"✅ †
prefixItems (tuple)prefixItems: [...]⚠️⚠️⚠️
dependentRequireddependentRequired: {...}⚠️✅ §⚠️
dependentSchemasdependentSchemas: {...}⚠️⚠️⚠️⚠️⚠️
unevaluatedPropertiesunevaluatedProperties: false⚠️✅ ¶⚠️
if/then/elseif: ... then: ... else: ...⚠️⚠️⚠️⚠️⚠️
$dynamicRef / $dynamicAnchor$dynamicRef: "#node"⚠️⚠️⚠️⚠️
$ref with siblingsSibling keywords ignoredSibling keywords honoured⚠️⚠️⚠️
patternPropertiespatternProperties: {...}✅ ‖✅ ‖✅ ‖✅ ‖⚠️
FeaturePythonJavaGoTypeScriptRubyC#
Parameters: in: query / in: path
Parameters: in: header
Parameters: in: cookie
Path-item-level parameter merging
Parameter style / explode (all 7 styles)
Parameter allowEmptyValue
Request body: application/json
Request body: multipart/form-data (file uploads)✅ Ⓒ
Request body: application/x-www-form-urlencoded
Request body: application/octet-stream✅ Ⓒ
Request body: application/xml / text/plain
Multi-content-type request bodies⚠️
Multipart encoding object (per-part headers/content-type)⚠️⚠️
Response body: application/json
Response body: binary / application/octet-stream
Response body: text/event-stream (SSE)
Response status: range codes (2XX/4XX/5XX)
Response status: default (typed errors)
Response headers (typed)
Typed error responses (4xx/5xx body schemas)
FeaturePythonJavaGoTypeScriptRubyC#
Multiple servers
Server variables (URL templating)
Per-path / per-operation servers⚠️
components.securitySchemes (apiKey, http, oauth2, openIdConnect, mutualTLS)✅ Ⓜ✅ Ⓜ
Global / per-operation security (AND/OR + opt-out)
OAuth2 client-credentials flow (built-in TokenSource)
OAuth2 authorization-code / implicit / password flows⚠️⚠️
$ref to non-schema components (parameters, responses, requestBodies, …)⚠️
3.1 components.pathItems⚠️⚠️
info.contact / info.license / info.termsOfService⚠️
Document-level externalDocs⚠️
tags (definitions + per-operation)
operationId collision detection⚠️
Vendor extensions (x-*) surfaced to SDK doc-comments
callbacks on operations (typed receivers)⚠️⚠️✅ ‡⚠️
3.1 top-level webhooks (typed receivers + Mux)
response.links / components.links⚠️⚠️

The ⚠️ rows are tracked for future work — open an issue if a specific keyword is blocking you and we’ll prioritise it.

† TypeScript const support covers primitive values (string, number, boolean, null). Object- and array-valued const still falls back to unknown.

‡ TypeScript exposes callbacks as a typed escape hatch — the SDK emits payload types you can use in your own webhook handler — rather than the runtime mux/dispatcher pattern the Go generator uses.

§ TypeScript surfaces dependentRequired as a @dependentRequired JSDoc tag on the generated interface plus an opt-in validate<TypeName>(obj) runtime helper that throws ValidationError if the constraint is violated. The generator never auto-invokes the validator — call it from your own ingest path when you want stricter runtime checks.

¶ TypeScript handles the unevaluatedProperties: false form (extra properties are forbidden). The generated interface emits a @strictProperties JSDoc tag and an opt-in validate<TypeName> runtime helper. The typed form (unevaluatedProperties: { type: ... }) still warns and degrades — it requires composition-aware validation that the opt-in helper does not cover.

‖ Single-regex patternProperties (one pattern, no fixed properties) is lifted to the language’s open-map type (Record<string, T> / map[string]T / Map<String, V> / dict[str, T]). Multi-pattern objects can’t carry per-regex value shapes in a static type, so they degrade. Ruby does not model patternProperties at all; C# degrades it with a SOX006 diagnostic.

Ⓡ Ruby surfaces numeric minimum / maximum / exclusive bounds as YARD doc tags only (not multipleOf), and emits no runtime constraint validation. String, array, and object constraints are not modelled.

Ⓒ C# multipart and octet-stream request bodies are runtime-verified by the conformance suite, but the emitter marks them with a SOX008 “partial support” info diagnostic — exotic per-part encodings may not round-trip.

mutualTLS: Python, Go, and TypeScript wire client certificates into the HTTP client directly. Ruby warns and expects you to configure the SSL context yourself; C# applies the scheme via default request headers.

What a degraded-feature diagnostic looks like

Section titled “What a degraded-feature diagnostic looks like”

For Python, Java, Go, and TypeScript, every degraded feature produces a stderr line in this format:

[soxom:warn] unsupported OpenAPI feature 'prefixItems' at #/components/schemas/Point/properties/coordinate

C# emits coded diagnostics instead:

warning: [SOX006] unsupported keyword `dependentRequired`; emitted type may be degraded (at #/components/schemas/Order/dependentRequired)

These lines surface in the live build log viewer and in your build’s stored log output. They do not count as build failures. (A C# build can fail if the spec itself is invalid — see the strict-parser note above.)

Pushing a spec to your Config Repository runs all enabled generators. Search the build log for [soxom:warn] (or SOX0 for C#) to see which features were degraded. If you need a clean run, switch the offending schema to a 2020-12-equivalent form that uses only supported keywords (often oneOf plus discriminator works in place of conditional schemas).

Real handling of the remaining ⚠️/❌ keywords (dependentSchemas, if/then/else, $dynamicRef, multi-pattern patternProperties) and cross-generator parity for the newer Ruby and C# columns is tracked on the generator roadmap. The degrade-and-continue behaviour above is the floor — generators graduate features from ⚠️ to ✅ as we add real codegen support.