Skip to content

Bind remaining OpenAPI 3.2 fields (query/additionalOperations/$self/querystring/mediaTypes) and validate them - #2402

Draft
khayashi4337 wants to merge 3 commits into
swagger-api:masterfrom
khayashi4337:openapi-3.2-full-support
Draft

khayashi4337 wants to merge 3 commits into
swagger-api:masterfrom
khayashi4337:openapi-3.2-full-support

Conversation

@khayashi4337

Copy link
Copy Markdown

Status: Draft — blocked on swagger-core releasing OAS 3.2 model support

This PR is not ready to merge. It builds on #2401 (already open, please
review that one first — it only makes swagger-parser accept "openapi": "3.2.x" and route it through the 3.1 code path, without populating any
3.2-only fields), and depends on model changes that only exist in a fork of
swagger-core (swagger-api/swagger-core#5326, itself a draft blocked on
#5253/#5254/#5255). pom.xml currently points at a locally-installed
2.2.56-SNAPSHOT that isn't available to anyone else — this PR cannot build
or pass CI until that lands upstream.

I opened it as a draft anyway so the parsing/validation work is visible and
reviewable in context, rather than sitting unpublished. I'll drop the
dependency on the fork and rebase once swagger-core cuts a release with the
3.2 model support.

What this adds (on top of #2401)

Actually reads the OAS 3.2-only fields into the parsed model, instead of
just tolerating the "3.2" version string:

  • PathItem.query, PathItem.additionalOperations, root $self,
    Parameter in: querystring (+ style: cookie), Components.mediaTypes,
    MediaType.$ref/itemSchema/prefixEncoding/itemEncoding, nested
    Encoding, and the simpler 3.2 fields (Server.name, Tag.*,
    Example.dataValue/serializedValue, etc.)
  • Reference resolution: the 3.1-family traversers/dereferencers now walk
    into all of the above (forward $id references, nested $refs inside
    additionalOperations/query/mediaTypes/encoding all resolve)
  • Semantic validation: in: querystring requires content and forbids
    schema/style/explode/allowReserved/allowEmptyValue; it can't
    coexist with in: query for the same effective parameter (checked within
    a parameter list, across path-item/operation level with correct override
    semantics, and through $ref to components.parameters); duplicate
    additionalOperations keys against the 8 fixed methods are flagged
    case-insensitively, matching the OAS 3.2 spec's own example
    (POST vs. fixed field post)

Known limitations (disclosed, not blocking this draft)

  • $self is bound as a field but not yet used as the base URI for reference
    resolution (OAS 3.2 gives it that role) — deferred.
  • A $ref to a parameter in an external document isn't checked for the
    query/querystring conflict (external refs aren't resolved at
    deserialize time) — disclosed as a known gap, not silently mishandled.
  • Referencing a boolean-valued schema (e.g. itemSchema: false via $ref)
    hits a pre-existing resolver defect (a BooleanNodeObjectNode cast)
    that this PR's new code paths expose but did not introduce.

Testing

Full reactor mvn install: 7 modules, all green. swagger-parser-v3 module
759 tests (733 TestNG + 26 separately-run JUnit classes), 0 failures.
OAI32DeserializationTest alone: 37 cases covering parsing, round-trips,
reference resolution, and the validation rules above.


🤖 Generated with Claude Code

… path

OpenAPI 3.2 builds on the 3.1 data model, so 3.2 documents are now
accepted wherever the 3.1-family code path is selected:

- OpenAPIDeserializer.parseRoot accepts "3.2" (loose prefix, matching the
  existing convention for "3.0"/"3.1") and sets the openapi31 flag
- the dotted-form warning check gains "3.2." so a bare "3.2" is accepted
  but reported as not a valid version field, same as bare "3.0"/"3.1"
- OpenAPIV3Parser.resolve and OpenAPIDereferencer31.canDereference route
  3.2 documents through the 3.1 dereferencer
- ResolverCache treats 3.2 as openapi31 so the 3.1 (JSON Schema 2020-12)
  Jackson mapper is selected for external-ref deserialization. This is
  load-bearing only for direct OpenAPIResolver callers (public API): the
  internal resolve() path routes 3.1/3.2 through OpenAPIDereferencer31
  and never constructs a ResolverCache for them
- canDereference gains a null guard on getOpenapi()

The openapi31 flag's meaning is widened from "3.1" to "3.1-family or
later". This is a stopgap: swagger-core's SpecVersion enum already exists
(V30/V31 today); once it gains a V32 value (swagger-core PR #5254/#5255
direction), this flag should be replaced with that.

3.2-only members (query operation, additionalOperations, $self, in:
querystring parameters) are reported as "attribute ... is unexpected" /
"is not of type" validation messages but are not reproduced in the
parsed model, so resolved output can differ from a fully 3.2-aware
parser. README notes the experimental handling.

Tests: OAI32DeserializationTest covers 3.2.0/3.2.1 parsing,
unexpected-attribute recording for 3.2-only fields, resolveFully
actually resolving refs, routing through the 3.1 dereferencer via
components.pathItems, bare "3.2" acceptance-with-warning, loose-prefix
"3.20.0" acceptance-with-warning (a prefix-match artifact, not true 3.x
support), 3.3.0 genuinely rejected (contrast with the 3.20.0 case), and
malformed "3.2." -- which parses without a warning, an inherited quirk
of the pre-existing convention that this change extends rather than
fixes, asserted explicitly so it doesn't silently drift if the 3.0/3.1
behavior changes later.

Reviewed by Codex and Fable (3 rounds each: initial, post-rebase, and
this follow-up); this revision addresses all rounds' findings.
- Bind 3.2-only fields into the model instead of reporting them as
  unexpected: $self, PathItem.query/additionalOperations, Parameter
  in=querystring and style=cookie, Components.mediaTypes, MediaType
  $ref/itemSchema/prefixEncoding/itemEncoding, Encoding nested
  encoding/prefixEncoding/itemEncoding, Server.name, Tag
  summary/parent/kind, ApiResponse.summary, Example
  dataValue/serializedValue, SecurityScheme deprecated/
  oauth2MetadataUrl, OAuthFlows.deviceAuthorization +
  OAuthFlow.deviceAuthorizationUrl, XML.nodeType,
  Discriminator.defaultMapping
- Add SwaggerParseResult.openapi32 and a version-aware spec key set so
  3.0/3.1 documents keep their historical behavior and error messages
  (invalid 'in' message still lists only query|header|path|cookie)
- Semantic validation per the 3.2 spec: querystring requires content
  and forbids schema/style/explode/allowReserved/allowEmptyValue;
  querystring+query coexistence checked within a parameter list and
  across path-item/operation parameters, including local
  components.parameters refs; duplicate fixed method names in
  additionalOperations are warned
- Resolution: propagate openapi32 into fragment parsing, use Json32
  mapper for deepcopy/ids cache on 3.2 documents, traverse
  PathItem.query/additionalOperations, Components.mediaTypes,
  MediaType.$ref/itemSchema/prefixEncoding/itemEncoding and nested
  Encoding fields
- Tests: 31 cases in OAI32DeserializationTest covering binding,
  JSON/YAML round-trips, callbacks/webhooks/components.pathItems,
  invalid inputs and resolveFully; swagger-core 2.2.56-SNAPSHOT
  (local 3f1fd6030)
- IdsTraverser: traverse mediaTypes, query, additionalOperations,
  itemSchema, and nested encodings so forward $id targets registered
  only in those 3.2 containers resolve correctly
- getComponents: assign this.components early and parse pathItems last
  so components.pathItems operations can resolve local parameter refs
- getAllOperationsInAPath: use PathItem.readOperations() so path
  template parameter validation covers query and additionalOperations
- getParameterDefinition: only resolve local #/ refs; external refs
  must not be compared against unrelated local parameters
- querystring conflict check: evaluate the effective parameter set
  (name+in dedup) so legitimate operation-level overrides do not warn
- OpenAPI31Traverser.traverseMediaType: keep root-local refs via
  shouldHandleRootLocalRefs/handleRootLocalRefs like other types,
  storing resolved values under components.mediaTypes
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