Skip to content

fix(openapi): emit valid 3.0 schemas when downgrading from 3.1#8225

Merged
soyuka merged 2 commits into
api-platform:4.3from
soyuka:fix/openapi-3.0-downgrade-schema
Jun 3, 2026
Merged

fix(openapi): emit valid 3.0 schemas when downgrading from 3.1#8225
soyuka merged 2 commits into
api-platform:4.3from
soyuka:fix/openapi-3.0-downgrade-schema

Conversation

@soyuka
Copy link
Copy Markdown
Member

@soyuka soyuka commented Jun 2, 2026

Summary

LegacyOpenApiNormalizer (triggered by ?spec_version=3.0.0 and api:openapi:export --spec-version=3.0.0) produced invalid OpenAPI 3.0 output because it only ran a shallow scan over components.schemas.*.properties.*. Problems with the previous code:

  • type: ['array', 'null'] + itemsanyOf: [{type:array},{type:null}] with an orphan items sibling (invalid in 3.0).
  • type: 'null' entries leaked through — null is not a valid type in OpenAPI 3.0.
  • No recursion into nested embeddables (properties.properties), items, additionalProperties, allOf/oneOf/anyOf.
  • Path-level inline schemas (requestBody.content.*.schema, responses.*.content.*.schema, parameters.*.schema) were never visited.
  • examplesexample conversion was also shallow.

Fix

Rewrite as a recursive schema walk:

  • Nullable types map to type: X, nullable: true (3.0 idiomatic), preserving items / properties / additionalProperties.
  • Multi non-null type unions fall back to anyOf + nullable: true.
  • Recursion through properties, patternProperties, items, additionalProperties, allOf, oneOf, anyOf, not, contains, propertyNames, if/then/else.
  • Walks paths.*.{method}.requestBody.content.*.schema, responses.*.content.*.schema, parameters.*.schema.
  • examplesexample applied recursively.

Test plan

  • Added src/OpenApi/Tests/Serializer/LegacyOpenApiNormalizerTest.php (10 cases) covering: untouched 3.1 default, nullable scalar, nullable array with items, nested embeddable, items recursion, allOf/oneOf/anyOf, additionalProperties, multi non-null union → anyOf, recursive examplesexample, path operation request body walk.
  • vendor/bin/phpunit src/OpenApi/Tests/Serializer/LegacyOpenApiNormalizerTest.php — 10/10 pass.
  • vendor/bin/phpunit src/Symfony/Tests/Action/DocumentationActionTest.php — 11/11 pass.
  • Remaining OpenApi suite failure (OpenApiFactoryTest::testInvoke description text) is pre-existing on 4.3, unrelated to this change.

Refs #6194 — addresses the embeddable nullable array case reported there for users who use the 3.0 downgrade as a workaround. The root issue (zircote/swagger-php not supporting OpenAPI 3.1) remains upstream.

soyuka added 2 commits June 2, 2026 17:55
LegacyOpenApiNormalizer used a shallow scan that converted
type: ['x', 'null'] to anyOf at the top-level properties only.
This produced invalid 3.0 output: orphan items keys, type: 'null'
entries (not a valid 3.0 type), and no recursion into nested
embeddables, items, allOf/oneOf/anyOf, or path-level inline
schemas.

Rewrite as a recursive walk that:
- maps nullable types to type + nullable: true (3.0 idiomatic);
- preserves items/properties/additionalProperties on nullable
  arrays and objects;
- recurses into properties, patternProperties, items,
  additionalProperties, allOf, oneOf, anyOf, not, contains,
  propertyNames, if/then/else;
- walks path operation requestBody, responses, and parameter
  schemas;
- converts examples to example recursively.

Refs api-platform#6194.
The 3.0 downgrade now emits the idiomatic type + nullable: true shape
instead of anyOf with a type: null branch.
@soyuka soyuka merged commit 7aed9d1 into api-platform:4.3 Jun 3, 2026
106 of 108 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant