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 |
Add comprehensive OpenAPI 3.1 / JSON Schema 2020-12 support: - Type arrays with null support (e.g., ["string", "null"]) - JSON Schema 2020-12 keywords: const, examples, prefixItems, contains, minContains, maxContains, patternProperties, dependentSchemas, propertyNames, unevaluatedItems, unevaluatedProperties - Conditional keywords: if/then/else, dependentRequired - ExclusiveBound union type for 3.0 (boolean) and 3.1 (numeric) exclusive bounds - Webhooks support with $ref resolution - Version detection helpers: IsOpenAPI3_0(), IsOpenAPI3_1() - Info.Summary and License.Identifier fields - JSON Schema 2020-12 validator via EnableJSONSchema2020() - Document-level validation option: EnableJSONSchema2020Validation() - Allow $ref alongside other keywords in 3.1 schemas - Handle "null" type in schema validation - Auto-detect 3.1 in cmd/validate Co-Authored-By: Chance Kirsch <> Co-Authored-By: RobbertDM <> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…, etc.) The loader's resolveSchemaRef only resolved $ref in pre-3.1 fields (items, properties, additionalProperties, not, allOf, anyOf, oneOf). References inside the new OpenAPI 3.1 / JSON Schema 2020-12 fields were silently left unresolved, causing nil Value pointers. This adds ref resolution for: prefixItems, contains, patternProperties, dependentSchemas, propertyNames, unevaluatedItems, unevaluatedProperties. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The OpenAPI-to-JSON-Schema transformation only recursed into pre-3.1 fields (properties, additionalProperties, items, not, oneOf, anyOf, allOf). Nested schemas inside 3.1 fields with OpenAPI 3.0-isms like nullable:true were not converted, causing incorrect validation. This adds recursion into: prefixItems, contains, patternProperties, dependentSchemas, propertyNames, unevaluatedItems, unevaluatedProperties. Also consolidates the properties/patternProperties/dependentSchemas map iteration into a single loop. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Schema.Validate() (used by doc.Validate()) recursively validates sub-schemas in Items, Properties, AdditionalProperties, etc. but did not recurse into the new OpenAPI 3.1 / JSON Schema 2020-12 fields. Invalid sub-schemas nested inside these fields went undetected. This adds validation for: prefixItems, contains, patternProperties, dependentSchemas, propertyNames, unevaluatedItems, unevaluatedProperties. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Make paths optional in 3.1 (required only in 3.0) - Add mutualTLS security scheme type validation - Validate license url/identifier mutual exclusivity - Enable JSON Schema 2020-12 validation in openapi3filter for 3.1 docs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add $id, $anchor, $dynamicRef, $dynamicAnchor identity keywords - Add contentMediaType, contentEncoding, contentSchema vocabulary - Add discriminator support for anyOf (was only oneOf) - Validate jsonSchemaDialect as valid URI Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- IsEmpty(): add missing checks for PrefixItems, Contains, MinContains, MaxContains, PatternProperties, DependentSchemas, PropertyNames, UnevaluatedItems, UnevaluatedProperties, Examples - JSONLookup(): add all 23 missing JSON Schema 2020-12 field cases - validate(): relax items requirement for arrays when in 3.1 mode or when prefixItems is present - transformOpenAPIToJSONSchema: clean up exclusiveMinimum/Maximum false, handle nullable:true without type field - MarshalYAML: only emit paths when non-nil (valid in 3.1) - visitConstOperation: use reflect.DeepEqual for json.Number comparison - Webhooks validation: use componentNames() for deterministic ordering Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rephrase text to not contain literal json struct tag syntax that triggers the json/yaml tag consistency check. 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>
- Add $comment keyword to Schema struct (MarshalYAML, UnmarshalJSON, IsEmpty, JSONLookup) - Fix PrefixItems type from []*SchemaRef to SchemaRefs for consistency with OneOf/AnyOf/AllOf and JSON Pointer support - Fix exclusiveBoundToBool data loss: preserve numeric bound value when converting OAS 3.1 exclusive bounds to OAS 2.0 - Auto-enable JSON Schema 2020-12 validation for OpenAPI 3.1 documents in doc.Validate() so library users don't need explicit opt-in - Add ref resolution tests for if/then/else and contentSchema - Add transform test for contentSchema with nullable nested schema - Add validate test for contentSchema with invalid sub-schema - Document breaking API changes in README (ExclusiveBound, PrefixItems) - Regenerate docs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add $schema keyword to Schema struct for per-schema dialect declaration - Add $defs keyword (Schemas map) for local reusable schema definitions, with full support: struct, marshal, unmarshal, IsEmpty, JSONLookup, validate (recurse), loader (resolve refs), transform (recurse) - Fix jsonSchemaDialect URI validation to require a scheme - Refactor discriminator resolution into shared helper to eliminate code duplication between oneOf and anyOf paths - Regenerate docs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
OpenAPI 3.1 adds Const (any) and Examples ([]any) fields to Schema. Like Enum/Default/Example, these can contain arbitrary JSON/YAML values that pick up __origin__ metadata from the YAML loader. Strip it on unmarshal to prevent false diffs and unexpected metadata in parsed values. Adds TestOrigin_ConstAndExamplesStripped regression test. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The origin-tracking YAML loader injects __origin__ as a key inside any map-valued field to record source location. However, typed Go maps (map[string]*Encoding, map[string]*ServerVariable, map[string]*PathItem) treat __origin__ as a real entry, causing false positive diffs when the same spec is loaded from two different file paths. Fix by deleting originKey from these three maps after JSON unmarshaling, mirroring the existing pattern used for Extensions and the unmarshalStringMapP helper already used by Content, Schemas, Headers, etc. Affected: - MediaType.Encoding (map[string]*Encoding) - Server.Variables (map[string]*ServerVariable) - T.Webhooks (map[string]*PathItem) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
In OpenAPI 3.0 / JSON Schema draft-07, $ref replaces its entire object so sibling keywords are silently ignored. In OpenAPI 3.1 / JSON Schema 2020-12, $ref and sibling keywords are both applied. Changes: - SchemaRef gains a `sibling *Schema` field (generated via refs.tmpl) - UnmarshalJSON populates sibling when non-extension fields appear alongside $ref - resolveSchemaRef applies sibling fields onto a copy of the resolved schema, but only for OAS 3.1+ documents (preserves 3.0 behaviour) - applySiblingSchemaFields overlays known annotation/metadata fields (deprecated, description, title, readOnly, writeOnly, example, externalDocs, default) using the extra[] field list so only explicitly present siblings are applied Test: TestOAS31_RefSiblingKeyword in loader_31_schema_refs_test.go loads a 3.1 spec where status has deprecated:true as a $ref sibling and asserts that the resolved Value carries Deprecated==true. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
refs.go header changed from "Code generated by go generate; DO NOT EDIT." to "Code generated by go generate using refs.tmpl; DO NOT EDIT refs.go." Update the committed go doc snapshot to match. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
a280a48 to
cdd3f1b
Compare
Note for reviewersThis PR has been rebased onto current Conflicts resolved during rebase:
Review guidance:
|
JSON Schema 2020-12 allows unevaluatedProperties and unevaluatedItems to be either a boolean or a schema object (e.g. `unevaluatedProperties: false`). The fields were typed as *SchemaRef, which caused an unmarshal error when encountering the boolean form. Introduce BoolSchema, a type that handles both boolean and schema forms (same pattern as AdditionalProperties), and use it for all three fields. AdditionalProperties becomes a type alias for BoolSchema so existing code continues to compile unchanged. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
e89dd3f to
da7268d
Compare
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
da7268d to
2532417
Compare
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 <>