Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/docs/openapi3.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2401,6 +2401,11 @@ func EnableExamplesValidation() ValidationOption
EnableExamplesValidation does the opposite of DisableExamplesValidation.
By default, all schema examples are validated.

func EnableJSONSchema2020Validation() ValidationOption
EnableJSONSchema2020Validation enables JSON Schema 2020-12 compliant
validation for OpenAPI 3.1 documents. This option should be used with
doc.Validate().

func EnableSchemaDefaultsValidation() ValidationOption
EnableSchemaDefaultsValidation does the opposite of
DisableSchemaDefaultsValidation. By default, schema default values are
Expand Down
4 changes: 4 additions & 0 deletions cmd/validate/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ func main() {
}

var opts []openapi3.ValidationOption
if doc.IsOpenAPI3_1() {
log.Println("Detected OpenAPI 3.1 document, enabling JSON Schema 2020-12 validation")
opts = append(opts, openapi3.EnableJSONSchema2020Validation())
}
if !*defaults {
opts = append(opts, openapi3.DisableSchemaDefaultsValidation())
}
Expand Down
8 changes: 7 additions & 1 deletion openapi3/example_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,17 @@ import "context"
func validateExampleValue(ctx context.Context, input any, schema *Schema) error {
opts := make([]SchemaValidationOption, 0, 2)

if vo := getValidationOptions(ctx); vo.examplesValidationAsReq {
vo := getValidationOptions(ctx)
if vo.examplesValidationAsReq {
opts = append(opts, VisitAsRequest())
} else if vo.examplesValidationAsRes {
opts = append(opts, VisitAsResponse())
}

if vo.jsonSchema2020ValidationEnabled {
opts = append(opts, EnableJSONSchema2020())
}

opts = append(opts, MultiErrors())

return schema.VisitJSON(input, opts...)
Expand Down
4 changes: 3 additions & 1 deletion openapi3/refs.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion openapi3/refs.tmpl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Code generated by go generate; DO NOT EDIT.
// Code generated by go generate using refs.tmpl; DO NOT EDIT refs.go.
package {{ .Package }}

import (
Expand Down Expand Up @@ -127,7 +127,13 @@ func (x *{{ $type.Name }}Ref) Validate(ctx context.Context, opts ...ValidationOp
}

if len(extras) != 0 {
{{- if eq $type.Name "Schema" }}
if !getValidationOptions(ctx).jsonSchema2020ValidationEnabled {
return fmt.Errorf("extra sibling fields: %+v", extras)
}
{{- else }}
return fmt.Errorf("extra sibling fields: %+v", extras)
{{- end }}
}

if v := x.Value; v != nil {
Expand Down
13 changes: 12 additions & 1 deletion openapi3/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -1084,7 +1084,10 @@ func (schema *Schema) IsEmpty() bool {

// Validate returns an error if Schema does not comply with the OpenAPI spec.
func (schema *Schema) Validate(ctx context.Context, opts ...ValidationOption) error {
// Apply document-level validation options to the context
ctx = WithValidationOptions(ctx, opts...)

// Perform schema validation with the options in context
_, err := schema.validate(ctx, []*Schema{})
return err
}
Expand Down Expand Up @@ -1206,6 +1209,10 @@ func (schema *Schema) validate(ctx context.Context, stack []*Schema) ([]*Schema,
return stack, errors.New("when schema type is 'array', schema 'items' must be non-null")
}
case TypeObject:
case TypeNull:
if !validationOpts.jsonSchema2020ValidationEnabled {
return stack, fmt.Errorf("unsupported 'type' value %q", schemaType)
}
default:
return stack, fmt.Errorf("unsupported 'type' value %q", schemaType)
}
Expand Down Expand Up @@ -1263,7 +1270,11 @@ func (schema *Schema) validate(ctx context.Context, stack []*Schema) ([]*Schema,
}

if v := schema.Default; v != nil && !validationOpts.schemaDefaultsValidationDisabled {
if err := schema.VisitJSON(v); err != nil {
opts := []SchemaValidationOption{}
if validationOpts.jsonSchema2020ValidationEnabled {
opts = append(opts, EnableJSONSchema2020())
}
if err := schema.VisitJSON(v, opts...); err != nil {
return stack, fmt.Errorf("invalid default: %w", err)
}
}
Expand Down
9 changes: 9 additions & 0 deletions openapi3/validation_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type ValidationOptions struct {
schemaExtensionsInRefProhibited bool
regexCompilerFunc RegexCompilerFunc
extraSiblingFieldsAllowed map[string]struct{}
jsonSchema2020ValidationEnabled bool // Enables JSON Schema 2020-12 compliant validation for OpenAPI 3.1
}

type validationOptionsKey struct{}
Expand All @@ -31,6 +32,14 @@ func AllowExtraSiblingFields(fields ...string) ValidationOption {
}
}

// EnableJSONSchema2020Validation enables JSON Schema 2020-12 compliant validation for OpenAPI 3.1 documents.
// This option should be used with doc.Validate().
func EnableJSONSchema2020Validation() ValidationOption {
return func(options *ValidationOptions) {
options.jsonSchema2020ValidationEnabled = true
}
}

// EnableSchemaFormatValidation makes Validate not return an error when validating documents that mention schema formats that are not defined by the OpenAPIv3 specification.
// By default, schema format validation is disabled.
func EnableSchemaFormatValidation() ValidationOption {
Expand Down