feat: add OpenAPI 3.1 support#1125
Conversation
Open issues are tracked in the PR getkin#1125 description instead. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Open Issues Status Update22 of 30 issues resolved across commits 9–11. Resolved issues (22)Bugs / correctness (11 fixed)
Missing features (3 added)
Code quality (2 fixed)
Breaking API changes (2 documented)
Test coverage (4 added)
Remaining open issues (8)These are larger-scope items for follow-up PRs:
|
Coverage vs Pierre Fenoll's Task ListAssessment of this PR against the tasks outlined by Pierre for complete OpenAPI 3.1 support:
What this PR delivers (~60-70% of the full task list)
Remaining items for follow-up PRs
|
Pass source file path to yaml3 decoder so origin locations include the file they were parsed from. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Open issues are tracked in the PR getkin#1125 description instead. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
da004e9 to
4e8f560
Compare
Open issues are tracked in the PR getkin#1125 description instead. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Open issues are tracked in the PR getkin#1125 description instead. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Open issues are tracked in the PR getkin#1125 description instead. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
e308c1f to
76c0438
Compare
Open issues are tracked in the PR getkin#1125 description instead. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Does this branch solve/allow this? |
|
Yes! This is now supported and tested. I just added a commit that:
So your spec is now handled correctly: status:
deprecated: true # sibling keyword — valid in OAS 3.1
$ref: '#/components/schemas/PingStatus'After loading, The fix is gated on the document version ( See |
Open issues are tracked in the PR getkin#1125 description instead. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
a280a48 to
cdd3f1b
Compare
Signed-off-by: Pierre Fenoll <pierrefenoll@gmail.com>
Signed-off-by: Pierre Fenoll <pierrefenoll@gmail.com>
Signed-off-by: Pierre Fenoll <pierrefenoll@gmail.com>
Signed-off-by: Pierre Fenoll <pierrefenoll@gmail.com>
Signed-off-by: Pierre Fenoll <pierrefenoll@gmail.com>
Signed-off-by: Pierre Fenoll <pierrefenoll@gmail.com>
Signed-off-by: Pierre Fenoll <pierrefenoll@gmail.com>
Signed-off-by: Pierre Fenoll <pierrefenoll@gmail.com>
Signed-off-by: Pierre Fenoll <pierrefenoll@gmail.com>
…idationOption) error Signed-off-by: Pierre Fenoll <pierrefenoll@gmail.com>
…TLS for v3.0 Signed-off-by: Pierre Fenoll <pierrefenoll@gmail.com>
Pierre's FIXME on PR #15: the helper previously covered only 8 fields (deprecated, description, title, readOnly, writeOnly, example, externalDocs, default). Extend to every field in the Schema struct so any sibling keyword alongside $ref in an OAS 3.1 document is correctly overlaid onto the resolved $ref target. Section comments dropped: the entire function runs only when the caller has already checked IsOpenAPI31OrLater(), so splitting cases by OAS version inside the switch was misleading. Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
Split the $ref sibling-fields check out of (*Ref).Validate into a dedicated validateExtras method, generated from refs.tmpl for every Ref type. This lets subsequent patches invoke validateExtras on SchemaRefs referenced from inside a schema tree — i.e. at the sites where Schema.validate recurses into nested SchemaRefs — without duplicating the check logic. Template update + `go generate` regeneration. No behaviour change: Validate still returns the same error for the same inputs; the check is just reachable from additional call sites. Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
…ression
TestSchemaRefSiblingKeyword/{3.0 false false} (added by @fenollp in
this PR) exposed that $ref sibling fields (e.g. description,
deprecated) were accepted on nested property schemas in OAS 3.0 when
they should have been rejected. Root cause: SchemaRef.validateExtras
was invoked only from SchemaRef.Validate, but nested schema
validation in Schema.validate recursed directly into
ref.Value.Validate, bypassing the ref-level extras check.
Invoke ref.validateExtras(ctx) at every nested SchemaRef site: items,
properties, additionalProperties, prefixItems, contains,
patternProperties, dependentSchemas, $defs, propertyNames,
unevaluatedItems, unevaluatedProperties, contentSchema, if/then/else.
Drop the t.Skip on TestSchemaRefSiblingKeyword now that all three
subcases pass.
Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
…o $ref
lxkns.yaml is OAS 3.0.2 and uses `description` as a sibling to $ref in
many places, which is invalid in OAS 3.0 ($ref replaces the enclosing
object; siblings are ignored). Previously this was silently accepted
because validateExtras was only invoked on top-level component refs.
Now that nested SchemaRefs are validated too, those siblings surface
as a validation error and mask the example-type mismatch this test
actually targets.
Pass AllowExtraSiblingFields("description") so validation proceeds to
the example-type assertion the test was written for (same pattern
already used in issue513_test.go:264).
Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
Per Pierre's PR #15 review: Schema.validate accepted OAS 3.1 / JSON Schema 2020-12 fields (prefixItems, contains, if/then/else, $defs, $schema, patternProperties, unevaluatedItems, etc.) on OAS 3.0 documents. Add a gate at the top of Schema.validate that rejects each 3.1-only field in 3.0 mode via errFieldFor31Plus. The gate honours AllowExtraSiblingFields so 3.0 documents that resolve external JSON Schema refs (draft-04, draft-07) can opt in to letting $id/$schema/etc. through. This matches the existing opt-in mechanism already used by TestExtraSiblingsInRemoteRef. This whole block becomes a no-op once OAS 3.0 gets its own standalone schema validator. Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
Three tests need adjustment now that OAS 3.1-only schema fields are
rejected under OAS 3.0 validation:
- TestSchemaIfThenElse_Validate and TestSchemaValidate31SubSchemas
exercise 3.1 features (If/Then/Else, PrefixItems) directly via
Schema.Validate without a doc, so the isOpenAPI31OrLater flag is
never set from a doc version. Pass IsOpenAPI31OrLater() explicitly.
- TestIssue495WithDraft04{,Bis} load OAS 3.0 documents that $ref
external JSON Schema draft-04 meta-schemas (which contain $id and
$schema). Add AllowExtraSiblingFields("$id", "$schema") so the
tests assertion about the unresolved inner "#" ref surfaces as
intended, matching the pattern already used in issue513_test.go.
Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
|
Alright! oasdiff#15 is rebased and ready to merge in here. |
A few edits on your v3.1 PR
|
Merged #15 into |
Open issues are tracked in the PR #1125 description instead. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rename the v0.132.0 entry to v0.136.0 (the upcoming release for this PR), move it above v0.135.0 for chronological order, and add the UnevaluatedItems/UnevaluatedProperties → BoolSchema type change. Addresses fenollp's review on #1125.
|
FYI the schema error conversion for 3.1 (formatValidationError) is probably not working as you intended. It returns null schema & value in the error. From #1155 I get this: |
Signed-off-by: Pierre Fenoll <pierrefenoll@gmail.com>
Signed-off-by: Pierre Fenoll <pierrefenoll@gmail.com>
|
Confirmed. Not a v0.136.0 blocker in my view since |
Summary
Comprehensive OpenAPI 3.1 / JSON Schema 2020-12 support. This consolidates and supersedes PRs #1102, #1114, #1118–#1124.
Core features
["string", "null"])const,examples,prefixItems,contains,minContains,maxContains,patternProperties,dependentSchemas,propertyNames,unevaluatedItems,unevaluatedPropertiesif/then/else,dependentRequired$id,$anchor,$dynamicRef,$dynamicAnchorcontentMediaType,contentEncoding,contentSchema$schema,$comment,$defsunevaluatedItemsandunevaluatedProperties: supports both boolean (false) and schema object forms, reusing the same pattern asAdditionalProperties$refresolutionIsOpenAPI3_0(),IsOpenAPI3_1()Validation
EnableJSONSchema2020()(per-field) andEnableJSONSchema2020Validation()(document-level)doc.Validate()automatically enables JSON Schema 2020-12 mode for OpenAPI 3.1 documentsconstkeyword enforcement,IsEmpty()awareness of all new fields$refresolution in loader for all new schema fields (including$defs)$defs)$refalongside other keywords (legal in 3.1)"null"type in schema validationBackward compatibility
ExclusiveBoundtransparently handles both boolean and numeric formsBoolSchemareuses the existingAdditionalPropertiespattern (type AdditionalProperties = BoolSchemaalias preserves backward compatibility)openapi2convupdated to convert betweenExclusiveBoundand boolean, preserving numeric bound valuesCommit history
BoolSchematype (withAdditionalPropertieskept as alias), handleunevaluatedProperties: falseandunevaluatedItems: false(fixes [3.1] Failed to unmarshal unevaluatedProperties: false (boolean form) oasdiff/oasdiff#844)Open issues for complete 3.1 support
The following items are known gaps that can be addressed in follow-up PRs:
Missing features
— Added per-schema dialect declaration.$schemakeyword— Added with full support (struct, marshal, unmarshal, IsEmpty, JSONLookup, validate, loader, transform).$defskeyword— Added as first-class field.$commentkeyword$dynamicRef/$dynamicAnchornot resolved — Parsed and serialized but the loader does not resolve them. Schemas using$dynamicReffor recursive references will not work.const. Other 3.1 keywords are silently ignored withoutEnableJSONSchema2020().contentMediaType/contentEncodingnot validated at runtime — Spec-compliant (annotation-only in 2020-12), but some users may expect validation.pathItemsin Components struct — OAS 3.1 addedcomponents/pathItems. Completely absent — silently dropped during parsing.Bugs / correctness
— All fields added.Schema.JSONLookup()missing all new 3.1 fields— All fields added.IsEmpty()missing checks for most new 3.1 fields— Relaxed.validate()requiresitemsfor typearrayeven in 3.1— Fixed.transformOpenAPIToJSONSchemadoes not clean upexclusiveMinimum: false— Fixed.transformOpenAPIToJSONSchemadropsnullable: truewithouttype— Fixed.MarshalYAMLunconditionally emits"paths": nullfor 3.1 docs— Fixed.visitConstOperationuses==forjson.NumberWebhooks validation iterates non-deterministically— Fixed.— Fixed.exclusiveBoundToBoolloses constraint data— Fixed.doc.Validate()does not auto-enable 3.1 mode— Now requires scheme.jsonSchemaDialectURI validation is a no-op— Fixed withunevaluatedProperties: false/unevaluatedItems: falsefails to unmarshalBoolSchematype.itemsto ALL array elements, ignoringprefixItems— In 3.1,itemsapplies only beyond theprefixItemstuple.patternPropertiesomission changesadditionalPropertiessemantics —additionalProperties: falseincorrectly rejects properties matching pattern properties.visitJSONWithJSONSchema— Silently falls back to built-in validator when JSON Schema compilation fails.Const: nilcannot express "value must be null" — Gonilis the zero value forany.Breaking API changes
— Documented in README.ExclusiveMin/ExclusiveMaxtype changed— Documented in README.PrefixItemstype changed—UnevaluatedItems/UnevaluatedPropertiestype changed from*SchemaReftoBoolSchemaAdditionalPropertieskept as type alias for backward compatibility.Code quality
— Changed toPrefixItemstype inconsistencySchemaRefs.Discriminator logic duplicated for— Refactored intoanyOfresolveDiscriminatorRefhelper.Test coverage
No ref resolution test for— Added.ContentSchemaNo ref resolution test for— Added.If/Then/ElseNo— Added.transformOpenAPIToJSONSchematest forContentSchemaNo— Added.Schema.validate()test forContentSchemaTest plan
go test ./...)Supersedes
Closes #1102, closes #1114, closes #1118, closes #1119, closes #1120, closes #1121, closes #1122, closes #1123, closes #1124
🤖 Generated with Claude Code
Co-Authored-By: Chance Kirsch <>
Co-Authored-By: RobbertDM <>