Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

openapi3: support format conditional on doc.openapi version #744

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
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
21 changes: 18 additions & 3 deletions .github/docs/openapi3.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,26 @@ const TypeArray = "array" ...
const FormatOfStringForUUIDOfRFC4122 = `^(?:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000)$` ...
const SerializationSimple = "simple" ...
var SchemaErrorDetailsDisabled = false ...
var ErrInvalidVersion ...
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's your rationale to export this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So one can check at loading time he got an invalid error version, not some other kind of error.

var CircularReferenceCounter = 3
var CircularReferenceError = "kin-openapi bug found: circular schema reference not handled"
var DefaultReadFromURI = URIMapCache(ReadFromURIs(ReadFromHTTP(http.DefaultClient), ReadFromFile))
var ErrURINotSupported = errors.New("unsupported URI")
var IdentifierRegExp = regexp.MustCompile(identifierPattern)
var SchemaStringFormats = make(map[string]Format, 4)
var SchemaStringFormats = make(map[string]*Format, 4)
func BoolPtr(value bool) *bool
func DefaultRefNameResolver(ref string) string
func DefineIPv4Format()
func DefineIPv6Format()
func DefineStringFormat(name string, pattern string)
func DefineStringFormatCallback(name string, callback FormatCallback)
func DefineStringFormat(name string, pattern string, options ...SchemaFormatOption)
func DefineStringFormatCallback(name string, callback FormatCallback, options ...SchemaFormatOption)
func Float64Ptr(value float64) *float64
func Int64Ptr(value int64) *int64
func ReadFromFile(loader *Loader, location *url.URL) ([]byte, error)
func RegisterArrayUniqueItemsChecker(fn SliceUniqueItemsChecker)
func RestoreDefaultStringFormats()
func RestoreStringFormats(formatToRestore map[string]*Format)
func SaveStringFormats(map[string]*Format) map[string]*Format
func Uint64Ptr(value uint64) *uint64
func ValidateIdentifier(value string) error
func WithValidationOptions(ctx context.Context, opts ...ValidationOption) context.Context
Expand Down Expand Up @@ -96,8 +100,12 @@ type Schema struct{ ... }
func NewArraySchema() *Schema
func NewBoolSchema() *Schema
func NewBytesSchema() *Schema
func NewDateSchema() *Schema
func NewDateTimeSchema() *Schema
func NewFloat64Schema() *Schema
func NewHostnameSchema() *Schema
func NewIPv4Schema() *Schema
func NewIPv6Schema() *Schema
func NewInt32Schema() *Schema
func NewInt64Schema() *Schema
func NewIntegerSchema() *Schema
Expand All @@ -107,6 +115,9 @@ type Schema struct{ ... }
func NewStringSchema() *Schema
func NewUUIDSchema() *Schema
type SchemaError struct{ ... }
type SchemaFormatOption func(options *SchemaFormatOptions)
func FromOpenAPIMinorVersion(fromMinorVersion uint64) SchemaFormatOption
type SchemaFormatOptions struct{ ... }
type SchemaRef struct{ ... }
func NewSchemaRef(ref string, value *Schema) *SchemaRef
type SchemaRefs []*SchemaRef
Expand All @@ -118,6 +129,7 @@ type SchemaValidationOption func(*schemaValidationSettings)
func EnableFormatValidation() SchemaValidationOption
func FailFast() SchemaValidationOption
func MultiErrors() SchemaValidationOption
func SetOpenAPIMinorVersion(minorVersion uint64) SchemaValidationOption
func SetSchemaErrorMessageCustomizer(f func(err *SchemaError) string) SchemaValidationOption
func VisitAsRequest() SchemaValidationOption
func VisitAsResponse() SchemaValidationOption
Expand Down Expand Up @@ -147,9 +159,12 @@ type ValidationOption func(options *ValidationOptions)
func DisableSchemaDefaultsValidation() ValidationOption
func DisableSchemaFormatValidation() ValidationOption
func DisableSchemaPatternValidation() ValidationOption
func DisableVersionValidation() ValidationOption
func EnableExamplesValidation() ValidationOption
func EnableSchemaDefaultsValidation() ValidationOption
func EnableSchemaFormatValidation() ValidationOption
func EnableSchemaPatternValidation() ValidationOption
func EnableVersionValidation() ValidationOption
type ValidationOptions struct{ ... }
type Version string
type XML struct{ ... }
2 changes: 2 additions & 0 deletions openapi3/issue735_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ func TestIssue735(t *testing.T) {
DefineStringFormat("email", FormatOfStringForEmail)
DefineIPv4Format()
DefineIPv6Format()
// restore modified string formats used during this tests
defer RestoreDefaultStringFormats()

testCases := []testCase{
{
Expand Down
2 changes: 1 addition & 1 deletion openapi3/loader_paths_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (

func TestPathsMustStartWithSlash(t *testing.T) {
spec := `
openapi: "3.0"
openapi: "3.0.0"
info:
version: "1.0"
title: sample
Expand Down
12 changes: 8 additions & 4 deletions openapi3/openapi3.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
type T struct {
Extensions map[string]interface{} `json:"-" yaml:"-"`

OpenAPI string `json:"openapi" yaml:"openapi"` // Required
OpenAPI Version `json:"openapi" yaml:"openapi"` // Required
Components *Components `json:"components,omitempty" yaml:"components,omitempty"`
Info *Info `json:"info" yaml:"info"` // Required
Paths Paths `json:"paths" yaml:"paths"` // Required
Expand Down Expand Up @@ -92,11 +92,15 @@ func (doc *T) AddServer(server *Server) {
func (doc *T) Validate(ctx context.Context, opts ...ValidationOption) error {
ctx = WithValidationOptions(ctx, opts...)

var wrap func(error) error

wrap = func(e error) error { return fmt.Errorf("invalid openapi value: %w", e) }
if doc.OpenAPI == "" {
return errors.New("value of openapi must be a non-empty string")
return wrap(errors.New("must be a non-empty string"))
}
if err := doc.OpenAPI.Validate(ctx); err != nil {
return wrap(err)
}

var wrap func(error) error

wrap = func(e error) error { return fmt.Errorf("invalid components: %w", e) }
if v := doc.Components; v != nil {
Expand Down
10 changes: 5 additions & 5 deletions openapi3/openapi3_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ func eqYAML(t *testing.T, expected, actual []byte) {
}

var specYAML = []byte(`
openapi: '3.0'
openapi: '3.0.0'
info:
title: MyAPI
version: '0.1'
Expand Down Expand Up @@ -153,7 +153,7 @@ components:

var specJSON = []byte(`
{
"openapi": "3.0",
"openapi": "3.0.0",
"info": {
"title": "MyAPI",
"version": "0.1"
Expand Down Expand Up @@ -266,7 +266,7 @@ func spec() *T {
}
example := map[string]string{"name": "Some example"}
return &T{
OpenAPI: "3.0",
OpenAPI: "3.0.0",
Info: &Info{
Title: "MyAPI",
Version: "0.1",
Expand Down Expand Up @@ -422,12 +422,12 @@ components:
{
name: "version is missing",
spec: strings.Replace(spec, version, "", 1),
expectedErr: "value of openapi must be a non-empty string",
expectedErr: "invalid openapi value: must be a non-empty string",
},
{
name: "version is empty string",
spec: strings.Replace(spec, version, "openapi: ''", 1),
expectedErr: "value of openapi must be a non-empty string",
expectedErr: "invalid openapi value: must be a non-empty string",
},
{
name: "info section is missing",
Expand Down
30 changes: 29 additions & 1 deletion openapi3/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -579,20 +579,48 @@ func NewStringSchema() *Schema {
}
}

func NewDateSchema() *Schema {
return &Schema{
Type: TypeString,
Format: "date",
}
}

func NewDateTimeSchema() *Schema {
return &Schema{
Type: TypeString,
Format: "date-time",
}
}

func NewHostnameSchema() *Schema {
return &Schema{
Type: TypeString,
Format: "hostname",
}
}

func NewUUIDSchema() *Schema {
return &Schema{
Type: TypeString,
Format: "uuid",
}
}

func NewIPv4Schema() *Schema {
return &Schema{
Type: TypeString,
Format: "ipv4",
}
}

func NewIPv6Schema() *Schema {
return &Schema{
Type: TypeString,
Format: "ipv6",
}
}

func NewBytesSchema() *Schema {
return &Schema{
Type: TypeString,
Expand Down Expand Up @@ -1628,7 +1656,7 @@ func (schema *Schema) visitJSONString(settings *schemaValidationSettings, value
var formatStrErr string
var formatErr error
if format := schema.Format; format != "" {
if f, ok := SchemaStringFormats[format]; ok {
if f := getSchemaStringFormats(format, settings.openapiMinorVersion); f != nil {
switch {
case f.regexp != nil && f.callback == nil:
if cp := f.regexp; !cp.MatchString(value) {
Expand Down
Loading
Loading