diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 8dbb0620f..9d9ff726f 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -176,6 +176,13 @@ jobs: Tag XML + - if: runner.os == 'Linux' + name: Ensure readableType() covers all possible values of resolved var + run: | + [[ "$(git grep -F 'var resolved ' -- openapi3/loader.go | awk '{print $4}' | sort | tr '\n' ' ')" = "$RESOLVEDS" ]] + env: + RESOLVEDS: 'Callback CallbackRef ExampleRef HeaderRef LinkRef ParameterRef PathItem RequestBodyRef ResponseRef SchemaRef SecuritySchemeRef ' + check-goimports: runs-on: ubuntu-latest steps: diff --git a/openapi3/issue759_test.go b/openapi3/issue759_test.go new file mode 100644 index 000000000..255d8b7b6 --- /dev/null +++ b/openapi3/issue759_test.go @@ -0,0 +1,34 @@ +package openapi3 + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestIssue759(t *testing.T) { + spec := []byte(` +openapi: 3.0.0 +info: + title: title + description: description + version: 0.0.0 +paths: + /slash: + get: + responses: + "200": + # Ref should point to a response, not a schema + $ref: "#/components/schemas/UserStruct" +components: + schemas: + UserStruct: + type: object +`[1:]) + + loader := NewLoader() + + doc, err := loader.LoadFromData(spec) + require.Nil(t, doc) + require.EqualError(t, err, `bad data in "#/components/schemas/UserStruct" (expecting ref to response object)`) +} diff --git a/openapi3/loader.go b/openapi3/loader.go index 7f389cdfe..51020111e 100644 --- a/openapi3/loader.go +++ b/openapi3/loader.go @@ -351,12 +351,41 @@ func (loader *Loader) resolveComponent(doc *T, ref string, path *url.URL, resolv return nil } if err := codec(cursor, resolved); err != nil { - return nil, nil, fmt.Errorf("bad data in %q", ref) + return nil, nil, fmt.Errorf("bad data in %q (expecting %s)", ref, readableType(resolved)) } return componentDoc, componentPath, nil default: - return nil, nil, fmt.Errorf("bad data in %q", ref) + return nil, nil, fmt.Errorf("bad data in %q (expecting %s)", ref, readableType(resolved)) + } +} + +func readableType(x interface{}) string { + switch x.(type) { + case *Callback: + return "callback object" + case *CallbackRef: + return "ref to callback object" + case *ExampleRef: + return "ref to example object" + case *HeaderRef: + return "ref to header object" + case *LinkRef: + return "ref to link object" + case *ParameterRef: + return "ref to parameter object" + case *PathItem: + return "pathItem object" + case *RequestBodyRef: + return "ref to requestBody object" + case *ResponseRef: + return "ref to response object" + case *SchemaRef: + return "ref to schema object" + case *SecuritySchemeRef: + return "ref to securityScheme object" + default: + panic(fmt.Sprintf("unreachable %T", x)) } }