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

WIP: Switch to gojsonschema #318

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
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
45 changes: 10 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,44 +155,19 @@ func xmlBodyDecoder(body []byte) (interface{}, error) {
}
```

## Custom function to check uniqueness of array items

By defaut, the library check unique items by below predefined function

```go
func isSliceOfUniqueItems(xs []interface{}) bool {
s := len(xs)
m := make(map[string]struct{}, s)
for _, x := range xs {
key, _ := json.Marshal(&x)
m[string(key)] = struct{}{}
}
return s == len(m)
}
```

In the predefined function using `json.Marshal` to generate a string can
be used as a map key which is to support check the uniqueness of an array
when the array items are objects or arrays. You can register
you own function according to your input data to get better performance:

```go
func main() {
// ...

// Register a customized function used to check uniqueness of array.
openapi3.RegisterArrayUniqueItemsChecker(arrayUniqueItemsChecker)

// ... other validate codes
}

func arrayUniqueItemsChecker(items []interface{}) bool {
// Check the uniqueness of the input slice
}
```

## Sub-v0 breaking API changes

### v0.???
OpenAPIv3 "in-house" schema validation was replaced with a correct JSON Schema implementation and conversion from OpenAPIv3 Schema to JSON Schema.
* Dropped `openapi3.ErrOneOfConflict`: now when a value matches more than one `oneOf` schemas the error string contains `Must validate one and only one schema (oneOf)`
* Dropped `openapi3.SchemaFormatValidationDisabled`: any `openapi3.Schema.Format` value is valid.
* Dropped `openapi3.FailFast() openapi3.SchemaValidationOption` and `openapi3.SchemaErrorDetailsDisabled`: validating values against schemas is offloaded to a third-party library that does not provide such a mechanism.
* Dropped `openapi3.RegisterArrayUniqueItemsChecker(openapi3.SliceUniqueItemsChecker)`: validating values against schemas is offloaded to a third-party library that does not provide such a mechanism.
* Dropped `openapi3.SchemaStringFormats`, `openapi3.FormatCallback`, `openapi3.Format`, `openapi3.FormatOfStringForUUIDOfRFC4122`, `openapi3.DefineStringFormat(...)` and `openapi3.DefineStringFormatCallback(...)`. If your special format is not already under [`gojsonschema.FormatCheckers`](https://pkg.go.dev/github.com/xeipuuv/gojsonschema#pkg-variables), first define a [`gojsonschema.FormatChecker`](https://pkg.go.dev/github.com/xeipuuv/gojsonschema#FormatChecker) and register it with [`gojsonschema.FormatCheckers.Add("my-format", myImpl{})`](https://pkg.go.dev/github.com/xeipuuv/gojsonschema#FormatCheckerChain.Add) *before compiling your schemas*.
* Dropped `openapi3.ErrSchemaInputNaN` and `openapi3.ErrSchemaInputInf`: OpenAPIv3 does not explicitly mention the related values.
* Replaced `openapi3.SchemaError` with `openapi3.SchemaValidationError` which wraps `[]gojsonschema.ResultError` and thus provides similar functionality and more.

### v0.61.0
* Renamed `openapi2.Swagger` to `openapi2.T`.
* Renamed `openapi2conv.FromV3Swagger` to `openapi2conv.FromV3`.
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ require (
github.com/go-openapi/jsonpointer v0.19.5
github.com/gorilla/mux v1.8.0
github.com/stretchr/testify v1.5.1
github.com/xeipuuv/gojsonschema v1.2.0
gopkg.in/yaml.v2 v2.3.0 // indirect
)
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down
38 changes: 38 additions & 0 deletions openapi3/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,46 @@ package openapi3
import (
"bytes"
"errors"
"strings"

"github.com/xeipuuv/gojsonschema"
)

// SchemaValidationError is a collection of errors
type SchemaValidationError []gojsonschema.ResultError

var _ error = (*SchemaValidationError)(nil)

func (e SchemaValidationError) Error() string {
var buff strings.Builder
for i, re := range []gojsonschema.ResultError(e) {
if i != 0 {
buff.WriteString("\n")
}
buff.WriteString(re.String())
}
return buff.String()
}

// Errors unwraps into much detailed errors.
// See https://pkg.go.dev/github.com/xeipuuv/gojsonschema#ResultError
func (e SchemaValidationError) Errors() []gojsonschema.ResultError {
return e
}

// JSONPointer returns a dot (.) delimited "JSON path" to the context of the first error.
func (e SchemaValidationError) JSONPointer() string {
return []gojsonschema.ResultError(e)[0].Field()
}

func (e SchemaValidationError) asMultiError() MultiError {
errs := make([]error, 0, len(e))
for _, re := range e {
errs = append(errs, errors.New(re.String()))
}
return errs
}

// MultiError is a collection of errors, intended for when
// multiple issues need to be reported upstream
type MultiError []error
Expand Down
41 changes: 41 additions & 0 deletions openapi3/openapi3.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"

"github.com/getkin/kin-openapi/jsoninfo"
"github.com/xeipuuv/gojsonschema"
)

// T is the root of an OpenAPI v3 document
Expand All @@ -19,6 +20,46 @@ type T struct {
Servers Servers `json:"servers,omitempty" yaml:"servers,omitempty"`
Tags Tags `json:"tags,omitempty" yaml:"tags,omitempty"`
ExternalDocs *ExternalDocs `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`

refd, refdAsReq, refdAsRep *gojsonschema.SchemaLoader
}

// CompileSchemas needs to be called before any use of VisitJSON*()
func (doc *T) CompileSchemas() error {
if err := doc.compileSchemas(newSchemaValidationSettings(VisitAsRequest())); err != nil {
return err
}
if err := doc.compileSchemas(newSchemaValidationSettings(VisitAsResponse())); err != nil {
return err
}
return doc.compileSchemas(newSchemaValidationSettings())
}

func (doc *T) compileSchemas(settings *schemaValidationSettings) (err error) {
docSchemas := doc.Components.Schemas
schemas := make(schemasJSON, len(docSchemas))
for name, docSchema := range docSchemas {
schemas[name] = docSchema.Value.fromOpenAPISchema(settings)
}
//FIXME merge loops
refd := gojsonschema.NewSchemaLoader()
for name, schema := range schemas {
absRef := "#/components/schemas/" + name
sl := gojsonschema.NewGoLoader(schema)
if err = refd.AddSchema(absRef, sl); err != nil {
return
}
}

switch {
case settings.asreq:
doc.refdAsReq = refd
case settings.asrep:
doc.refdAsRep = refd
default:
doc.refd = refd
}
return
}

func (doc *T) MarshalJSON() ([]byte, error) {
Expand Down
Loading