Supported OpenAPI versions
A stability promise is only meaningful against a declared input surface. This page states exactly which OpenAPI versions the generator accepts, what it does and does not handle per version, and how the 3.0 and 3.1 spellings of the same construct are normalized to one code path.
Version matrix
Section titled “Version matrix”| Version | Status | Notes |
|---|---|---|
| OpenAPI 3.1.x | Supported | The primary target. Most constructs are exercised by the 3.1 conformance fixture. See the 3.1 exceptions below. |
| OpenAPI 3.0.x | Supported | The 3.0-divergent spellings (nullable: true, boolean exclusive bounds) are handled on dedicated code paths and pinned by a 3.0 conformance fixture. |
| OpenAPI 3.2.x | Accepted best-effort | Accepted with a loud generate-time warning that 3.2 is not fully supported, plus one warning per 3.2-only construct the generator drops: query method operations, additionalOperations, and itemSchema media types. The drift gate (openapi:check) surfaces the same warnings. Each dropped construct is also recorded in the per-spec unsupported constructs report. Full 3.2 support is tracked in issue #102. |
| OpenAPI 3.3+ or any 4.x | Rejected | The gate is exact, not a 3. prefix check: an unknown 3.x minor is rejected with an error naming this matrix rather than silently generating an incomplete API surface. |
Swagger 2.0 (swagger: "2.0") | Rejected | Has no openapi: version key, so it is rejected with a clear error. Convert to OpenAPI 3.x first. |
| Any other or missing version | Rejected | A document without a supported openapi: version string, or without an info object, is rejected up front rather than silently parsing into an empty result. |
What “supported” covers
Section titled “What “supported” covers”Across both 3.0.x and 3.1.0, the generator handles the common modeling surface: object schemas with properties, $refs between component schemas, allOf composition (merged into a flat class), additionalProperties maps, oneOf / anyOf (scalar unions emit native PHP unions, discriminated object unions are validated and hydrated, undiscriminated ones are presence-only), enums (native PHP backed enums), arrays and nested objects (DataCollection), the readOnly / writeOnly split, and scalar constraints (minLength, maxLength, pattern, format, minimum / maximum, exclusiveMinimum / exclusiveMaximum, multipleOf, uniqueItems, enum, const, default). The limitations guide documents the exact behavior and the honest residuals for each.
The matrix below is only about what differs between the two versions, since that is where a “which version is supported” question actually bites.
3.0 versus 3.1: how the spellings are normalized
Section titled “3.0 versus 3.1: how the spellings are normalized”OpenAPI 3.1 realigned with JSON Schema, so several constructs have two legal spellings depending on the document version. The generator normalizes each pair to a single internal representation, so the same construct produces the same output regardless of which version spelled it.
Nullability
Section titled “Nullability”| OpenAPI 3.0.x | OpenAPI 3.1.0 | |
|---|---|---|
| Spelling | type: string plus nullable: true | type: ["string", "null"] (a type array including "null") |
| Handled | Yes | Yes |
Both forms produce a nullable PHP property (?string, defaulting to = null) with nullable in the generated rules(). The 3.1 type-array form is recognized: a ["string", "null"] resolves to a nullable scalar, not a multi-type union. A type array with two real types (for example ["string", "integer"]) is a genuine multi-type union and is handled separately (see below).
Exclusive bounds
Section titled “Exclusive bounds”| OpenAPI 3.0.x | OpenAPI 3.1.0 | |
|---|---|---|
| Spelling | minimum: N plus exclusiveMinimum: true (boolean companion) | exclusiveMinimum: N (a numeric keyword on its own) |
| Handled | Yes | Yes |
Both emit a strict bound: gt:N for an exclusive minimum, lt:N for an exclusive maximum. Inclusive minimum / maximum emit min: / max:. The generator reads the schema’s serialized data to tell an explicit exclusiveMinimum: false (inclusive) apart from the parser’s default, so a 3.0 inclusive bound is never mistaken for an exclusive one.
Boolean items (3.1 only)
Section titled “Boolean items (3.1 only)”| OpenAPI 3.0.x | OpenAPI 3.1.0 | |
|---|---|---|
items: true | not legal | rewritten to items: {} (an “any” schema) |
items: false | not legal | the key is dropped; next to prefixItems the closed-tuple length survives as a synthesized maxItems |
OpenAPI 3.1 allows a boolean items. The vendored parser cannot instantiate a schema from a boolean, so a pre-parse normalizer rewrites boolean items before the parser sees it: true becomes an empty any-schema, false is dropped. When items: false sits next to a non-empty prefixItems list (the canonical closed-tuple spelling), the tuple length is preserved as a synthesized maxItems of the tuple size, which the emitter enforces as a max: count rule. This is faithful to JSON Schema and avoids inventing a fake “match nothing” schema.
Multi-type arrays (3.1 only)
Section titled “Multi-type arrays (3.1 only)”The JSON Schema multi-type form type: ["string", "integer"] (two or more real types) is a 3.1 construct. It is handled as a native PHP union (string|int) with presence-only rules, reusing the same union machinery as oneOf / anyOf. The special case ["string", "null"] (one real type plus "null") is treated as a nullable scalar, not a union, as noted under nullability.
const (3.1 only)
Section titled “const (3.1 only)”const (the JSON Schema single-value form) is a 3.1 construct. It is treated as a one-value enum: the property keeps its concrete type and gains a single-value Rule::in([...]) constraint. See const is a single-value enum.
dependentRequired (3.1 only)
Section titled “dependentRequired (3.1 only)”dependentRequired (the JSON Schema conditional-presence form) is a 3.1 construct. Each entry trigger: [dependent, ...] is translated into a required_with:trigger rule on the dependent property, so the dependent is required exactly when the trigger key is present. A dependent listed under several triggers merges them into one required_with:a,b rule (any present trigger requires it, matching JSON Schema’s per-entry implication), and a nullable dependent gets present_with: instead so a present null is not falsely rejected. The richer dependentSchemas applicator remains out of scope (see below).
String-typed scalar keywords (both versions, lenient)
Section titled “String-typed scalar keywords (both versions, lenient)”Some generators (across both versions) emit numeric keywords or the nullable flag as JSON strings, for example "minimum": "8" or "nullable": "true". The normalizer coerces the unambiguous cases (a strictly-numeric string, the literals "true" / "false") to their proper types so the constraint is not silently dropped. Anything ambiguous is left untouched. This is a robustness affordance, not a spec requirement.
3.1 features that are out of scope
Section titled “3.1 features that are out of scope”3.1 support is real, but it has declared boundaries. The following 3.1 (or JSON Schema) features are not generated from, by design:
webhooks(the 3.1 top-levelwebhooksobject). The generator does not emit controllers, routes, or Data classes fromwebhooks. Onlypathsdrives the server scaffold. A spec withwebhooksstill generates cleanly from itscomponentsandpaths; thewebhooksentries are simply not a generation source.- Tuple
prefixItemstyping. A positional tuple degrades toarray<int, mixed>rather than a per-position typed structure. Validation does NOT degrade: each tuple position gets its own per-index rule (field.0,field.1, …) from its position schema, and the closed form (items: false) enforces the tuple length as amax:count rule. See tuple prefixItems in the limitations guide. - Advanced JSON Schema applicators beyond
allOf/oneOf/anyOf:if/then/else,not,dependentSchemas,patternProperties, andunevaluatedPropertiesare not translated into rules (dependentRequired, the simpler presence-only sibling ofdependentSchemas, IS translated, see above). A schema using them still generates a class from its plainproperties; the conditional or pattern constraints are not enforced. One carve-out: underadditionalProperties: false,patternPropertiespatterns do widen the closed-object rule’s key allow-list so spec-legal keys are not falsely rejected (key admission only, the value schemas stay unenforced). See patternProperties under a closed object. additionalProperties: falseis enforced by default: undeclared keys are rejected because the spec is the source of truth. The--no-enforce-closed-objectsflag opts out for lenient, forward-compatible output during contract evolution. See additionalProperties: false.
These are completeness gaps, not crashes. Even a schema that leans on an unsupported feature produces code that parses and compiles; the unsupported part is simply not represented in the generated rules. Every such gap is also recorded in the per-spec unsupported constructs report, so you can see which of these boundaries actually applies to your document rather than reading a fixed list.
Validation mode
Section titled “Validation mode”The parser is invoked with full OpenAPI validation off by default. It applies the lightweight structural check above (version string plus info object) rather than asserting the document is fully spec-conformant. This is deliberate: many real-world specs in the wild are slightly non-conformant yet still useful, and the corpus gate proves the generator produces valid PHP for 135 of them. Strict validation can be opted into at the parser level, but the shipped commands run in lenient mode so a minor spec wart does not block generation.
Summary
Section titled “Summary”- OpenAPI 3.0.x and 3.1.x are supported. Both are pinned by a conformance fixture and exercised by the 135-spec corpus.
- OpenAPI 3.2.x is accepted best-effort: a loud warning plus one warning per dropped 3.2-only construct (
queryoperations,additionalOperations,itemSchema), on generate and on the drift gate alike. Each dropped construct is also recorded in the unsupported constructs report. Full support is tracked in issue #102. - Swagger 2.0 and any other version are rejected with a clear error naming this matrix.
- The 3.0 and 3.1 spellings of nullability and exclusive bounds are normalized to one code path; boolean
items, multi-type arrays,const, anddependentRequiredare 3.1-only constructs that are handled. webhooks, tupleprefixItemstyping, and advanced JSON Schema applicators are the declared 3.1 boundaries: not generated from or not represented in types, by design (tuple positions ARE validated through per-index rules).additionalProperties: falseis enforced by default, with--no-enforce-closed-objectsas the lenient opt-out. All documented here and in Limitations.