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

openapi{2,3}: simplify unmarshal errors #870

Merged
merged 1 commit into from
Nov 26, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 26 additions & 0 deletions openapi2/marsh.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package openapi2

import (
"encoding/json"
"fmt"
"strings"

"github.com/invopop/yaml"
)

func unmarshalError(jsonUnmarshalErr error) error {
if before, after, found := strings.Cut(jsonUnmarshalErr.Error(), "Bis."); found && before != "" && after != "" {
before = strings.ReplaceAll(before, " Go struct ", " ")
return fmt.Errorf("%s.%s", before, after)
}
return jsonUnmarshalErr
}

func unmarshal(data []byte, v interface{}) error {
// See https://github.com/getkin/kin-openapi/issues/680
if err := json.Unmarshal(data, v); err != nil {
// UnmarshalStrict(data, v) TODO: investigate how ymlv3 handles duplicate map keys
return yaml.Unmarshal(data, v)
}
return nil
}
61 changes: 61 additions & 0 deletions openapi2/marsh_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package openapi2

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestUnmarshalError(t *testing.T) {
{
v2 := []byte(`
openapi: '2.0'
info:
version: '1.10'
title: title
paths:
"/ping":
post:
consumes:
- multipart/form-data
parameters:
name: file # <-- Missing dash
in: formData
description: file
required: true
type: file
responses:
'200':
description: OK
`[1:])

var doc T
err := unmarshal(v2, &doc)
require.ErrorContains(t, err, `json: cannot unmarshal object into field Operation.parameters of type openapi2.Parameters`)
}

v2 := []byte(`
openapi: '2.0'
info:
version: '1.10'
title: title
paths:
"/ping":
post:
consumes:
- multipart/form-data
parameters:
- name: file # <--
in: formData
description: file
required: true
type: file
responses:
'200':
description: OK
`[1:])

var doc T
err := unmarshal(v2, &doc)
require.NoError(t, err)
}
2 changes: 1 addition & 1 deletion openapi2/openapi2.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func (doc *T) UnmarshalJSON(data []byte) error {
type TBis T
var x TBis
if err := json.Unmarshal(data, &x); err != nil {
return err
return unmarshalError(err)
}
_ = json.Unmarshal(data, &x.Extensions)
delete(x.Extensions, "swagger")
Expand Down
2 changes: 1 addition & 1 deletion openapi2/operation.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func (operation *Operation) UnmarshalJSON(data []byte) error {
type OperationBis Operation
var x OperationBis
if err := json.Unmarshal(data, &x); err != nil {
return err
return unmarshalError(err)
}
_ = json.Unmarshal(data, &x.Extensions)
delete(x.Extensions, "summary")
Expand Down
2 changes: 1 addition & 1 deletion openapi2/parameter.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ func (parameter *Parameter) UnmarshalJSON(data []byte) error {
type ParameterBis Parameter
var x ParameterBis
if err := json.Unmarshal(data, &x); err != nil {
return err
return unmarshalError(err)
}
_ = json.Unmarshal(data, &x.Extensions)
delete(x.Extensions, "$ref")
Expand Down
2 changes: 1 addition & 1 deletion openapi2/path_item.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func (pathItem *PathItem) UnmarshalJSON(data []byte) error {
type PathItemBis PathItem
var x PathItemBis
if err := json.Unmarshal(data, &x); err != nil {
return err
return unmarshalError(err)
}
_ = json.Unmarshal(data, &x.Extensions)
delete(x.Extensions, "$ref")
Expand Down
2 changes: 1 addition & 1 deletion openapi2/response.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func (response *Response) UnmarshalJSON(data []byte) error {
type ResponseBis Response
var x ResponseBis
if err := json.Unmarshal(data, &x); err != nil {
return err
return unmarshalError(err)
}
_ = json.Unmarshal(data, &x.Extensions)
delete(x.Extensions, "$ref")
Expand Down
2 changes: 1 addition & 1 deletion openapi2/security_scheme.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func (securityScheme *SecurityScheme) UnmarshalJSON(data []byte) error {
type SecuritySchemeBis SecurityScheme
var x SecuritySchemeBis
if err := json.Unmarshal(data, &x); err != nil {
return err
return unmarshalError(err)
}
_ = json.Unmarshal(data, &x.Extensions)
delete(x.Extensions, "$ref")
Expand Down
2 changes: 1 addition & 1 deletion openapi3/components.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func (components *Components) UnmarshalJSON(data []byte) error {
type ComponentsBis Components
var x ComponentsBis
if err := json.Unmarshal(data, &x); err != nil {
return err
return unmarshalError(err)
}
_ = json.Unmarshal(data, &x.Extensions)
delete(x.Extensions, "schemas")
Expand Down
2 changes: 1 addition & 1 deletion openapi3/contact.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func (contact *Contact) UnmarshalJSON(data []byte) error {
type ContactBis Contact
var x ContactBis
if err := json.Unmarshal(data, &x); err != nil {
return err
return unmarshalError(err)
}
_ = json.Unmarshal(data, &x.Extensions)
delete(x.Extensions, "name")
Expand Down
2 changes: 1 addition & 1 deletion openapi3/discriminator.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func (discriminator *Discriminator) UnmarshalJSON(data []byte) error {
type DiscriminatorBis Discriminator
var x DiscriminatorBis
if err := json.Unmarshal(data, &x); err != nil {
return err
return unmarshalError(err)
}
_ = json.Unmarshal(data, &x.Extensions)
delete(x.Extensions, "propertyName")
Expand Down
2 changes: 1 addition & 1 deletion openapi3/encoding.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func (encoding *Encoding) UnmarshalJSON(data []byte) error {
type EncodingBis Encoding
var x EncodingBis
if err := json.Unmarshal(data, &x); err != nil {
return err
return unmarshalError(err)
}
_ = json.Unmarshal(data, &x.Extensions)
delete(x.Extensions, "contentType")
Expand Down
2 changes: 1 addition & 1 deletion openapi3/example.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func (example *Example) UnmarshalJSON(data []byte) error {
type ExampleBis Example
var x ExampleBis
if err := json.Unmarshal(data, &x); err != nil {
return err
return unmarshalError(err)
}
_ = json.Unmarshal(data, &x.Extensions)
delete(x.Extensions, "summary")
Expand Down
2 changes: 1 addition & 1 deletion openapi3/external_docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func (e *ExternalDocs) UnmarshalJSON(data []byte) error {
type ExternalDocsBis ExternalDocs
var x ExternalDocsBis
if err := json.Unmarshal(data, &x); err != nil {
return err
return unmarshalError(err)
}
_ = json.Unmarshal(data, &x.Extensions)
delete(x.Extensions, "description")
Expand Down
2 changes: 1 addition & 1 deletion openapi3/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func (info *Info) UnmarshalJSON(data []byte) error {
type InfoBis Info
var x InfoBis
if err := json.Unmarshal(data, &x); err != nil {
return err
return unmarshalError(err)
}
_ = json.Unmarshal(data, &x.Extensions)
delete(x.Extensions, "title")
Expand Down
2 changes: 1 addition & 1 deletion openapi3/license.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func (license *License) UnmarshalJSON(data []byte) error {
type LicenseBis License
var x LicenseBis
if err := json.Unmarshal(data, &x); err != nil {
return err
return unmarshalError(err)
}
_ = json.Unmarshal(data, &x.Extensions)
delete(x.Extensions, "name")
Expand Down
2 changes: 1 addition & 1 deletion openapi3/link.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func (link *Link) UnmarshalJSON(data []byte) error {
type LinkBis Link
var x LinkBis
if err := json.Unmarshal(data, &x); err != nil {
return err
return unmarshalError(err)
}
_ = json.Unmarshal(data, &x.Extensions)
delete(x.Extensions, "operationRef")
Expand Down
11 changes: 0 additions & 11 deletions openapi3/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ import (
"sort"
"strconv"
"strings"

"github.com/invopop/yaml"
)

var CircularReferenceError = "kin-openapi bug found: circular schema reference not handled"
Expand Down Expand Up @@ -178,15 +176,6 @@ func (loader *Loader) loadFromDataWithPathInternal(data []byte, location *url.UR
return doc, nil
}

func unmarshal(data []byte, v interface{}) error {
// See https://github.com/getkin/kin-openapi/issues/680
if err := json.Unmarshal(data, v); err != nil {
// UnmarshalStrict(data, v) TODO: investigate how ymlv3 handles duplicate map keys
return yaml.Unmarshal(data, v)
}
return nil
}

// ResolveRefsIn expands references if for instance spec was just unmarshaled
func (loader *Loader) ResolveRefsIn(doc *T, location *url.URL) (err error) {
if loader.Context == nil {
Expand Down
26 changes: 26 additions & 0 deletions openapi3/marsh.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package openapi3

import (
"encoding/json"
"fmt"
"strings"

"github.com/invopop/yaml"
)

func unmarshalError(jsonUnmarshalErr error) error {
if before, after, found := strings.Cut(jsonUnmarshalErr.Error(), "Bis."); found && before != "" && after != "" {
before = strings.ReplaceAll(before, " Go struct ", " ")
return fmt.Errorf("%s.%s", before, after)
}
return jsonUnmarshalErr
}

func unmarshal(data []byte, v interface{}) error {
// See https://github.com/getkin/kin-openapi/issues/680
if err := json.Unmarshal(data, v); err != nil {
// UnmarshalStrict(data, v) TODO: investigate how ymlv3 handles duplicate map keys
return yaml.Unmarshal(data, v)
}
return nil
}
78 changes: 78 additions & 0 deletions openapi3/marsh_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package openapi3

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestUnmarshalError(t *testing.T) {
{
spec := []byte(`
openapi: 3.0.1
info:
version: v1
title: Products api
components:
schemas:
someSchema:
type: object
schemaArray:
type: array
minItems: 1
items:
$ref: '#/components/schemas/someSchema'
paths:
/categories:
get:
responses:
'200':
description: ''
content:
application/json:
schema:
allOf:
$ref: '#/components/schemas/schemaArray' # <- Should have been a list
`[1:])

sl := NewLoader()

_, err := sl.LoadFromData(spec)
require.ErrorContains(t, err, `json: cannot unmarshal object into field Schema.allOf of type openapi3.SchemaRefs`)
}

spec := []byte(`
openapi: 3.0.1
info:
version: v1
title: Products api
components:
schemas:
someSchema:
type: object
schemaArray:
type: array
minItems: 1
items:
$ref: '#/components/schemas/someSchema'
paths:
/categories:
get:
responses:
'200':
description: ''
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/schemaArray' # <-
`[1:])

sl := NewLoader()

doc, err := sl.LoadFromData(spec)
require.NoError(t, err)

err = doc.Validate(sl.Context)
require.NoError(t, err)
}
2 changes: 1 addition & 1 deletion openapi3/media_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func (mediaType *MediaType) UnmarshalJSON(data []byte) error {
type MediaTypeBis MediaType
var x MediaTypeBis
if err := json.Unmarshal(data, &x); err != nil {
return err
return unmarshalError(err)
}
_ = json.Unmarshal(data, &x.Extensions)
delete(x.Extensions, "schema")
Expand Down
2 changes: 1 addition & 1 deletion openapi3/openapi3.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func (doc *T) UnmarshalJSON(data []byte) error {
type TBis T
var x TBis
if err := json.Unmarshal(data, &x); err != nil {
return err
return unmarshalError(err)
}
_ = json.Unmarshal(data, &x.Extensions)
delete(x.Extensions, "openapi")
Expand Down
2 changes: 1 addition & 1 deletion openapi3/operation.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ func (operation *Operation) UnmarshalJSON(data []byte) error {
type OperationBis Operation
var x OperationBis
if err := json.Unmarshal(data, &x); err != nil {
return err
return unmarshalError(err)
}
_ = json.Unmarshal(data, &x.Extensions)
delete(x.Extensions, "tags")
Expand Down
2 changes: 1 addition & 1 deletion openapi3/parameter.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ func (parameter *Parameter) UnmarshalJSON(data []byte) error {
type ParameterBis Parameter
var x ParameterBis
if err := json.Unmarshal(data, &x); err != nil {
return err
return unmarshalError(err)
}
_ = json.Unmarshal(data, &x.Extensions)

Expand Down
2 changes: 1 addition & 1 deletion openapi3/path_item.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func (pathItem *PathItem) UnmarshalJSON(data []byte) error {
type PathItemBis PathItem
var x PathItemBis
if err := json.Unmarshal(data, &x); err != nil {
return err
return unmarshalError(err)
}
_ = json.Unmarshal(data, &x.Extensions)
delete(x.Extensions, "$ref")
Expand Down