diff --git a/openapi3/loader.go b/openapi3/loader.go index da3479770..c42d8ba63 100644 --- a/openapi3/loader.go +++ b/openapi3/loader.go @@ -35,6 +35,8 @@ type Loader struct { Context context.Context + rootDir string + visitedPathItemRefs map[string]struct{} visitedDocuments map[string]*T @@ -66,6 +68,7 @@ func (loader *Loader) LoadFromURI(location *url.URL) (*T, error) { // LoadFromFile loads a spec from a local file path func (loader *Loader) LoadFromFile(location string) (*T, error) { + loader.rootDir = path.Dir(location) return loader.LoadFromURI(&url.URL{Path: filepath.ToSlash(location)}) } @@ -415,6 +418,14 @@ func drillIntoField(cursor interface{}, fieldName string) (interface{}, error) { } } +func (loader *Loader) documentPathForRecursiveRef(current *url.URL, resolvedRef string) *url.URL { + if loader.rootDir == "" { + return current + } + return &url.URL{Path: path.Join(loader.rootDir, resolvedRef)} + +} + func (loader *Loader) resolveRef(doc *T, ref string, path *url.URL) (*T, string, *url.URL, error) { if ref != "" && ref[0] == '#' { return doc, ref, path, nil @@ -474,6 +485,7 @@ func (loader *Loader) resolveHeaderRef(doc *T, component *HeaderRef, documentPat return err } component.Value = resolved.Value + documentPath = loader.documentPathForRecursiveRef(documentPath, resolved.Ref) } } value := component.Value @@ -521,6 +533,7 @@ func (loader *Loader) resolveParameterRef(doc *T, component *ParameterRef, docum return err } component.Value = resolved.Value + documentPath = loader.documentPathForRecursiveRef(documentPath, resolved.Ref) } } value := component.Value @@ -577,6 +590,7 @@ func (loader *Loader) resolveRequestBodyRef(doc *T, component *RequestBodyRef, d return err } component.Value = resolved.Value + documentPath = loader.documentPathForRecursiveRef(documentPath, resolved.Ref) } } value := component.Value @@ -632,6 +646,7 @@ func (loader *Loader) resolveResponseRef(doc *T, component *ResponseRef, documen return err } component.Value = resolved.Value + documentPath = loader.documentPathForRecursiveRef(documentPath, resolved.Ref) } } value := component.Value @@ -701,6 +716,7 @@ func (loader *Loader) resolveSchemaRef(doc *T, component *SchemaRef, documentPat return err } component.Value = resolved.Value + documentPath = loader.documentPathForRecursiveRef(documentPath, resolved.Ref) } } value := component.Value @@ -778,6 +794,7 @@ func (loader *Loader) resolveSecuritySchemeRef(doc *T, component *SecurityScheme return err } component.Value = resolved.Value + documentPath = loader.documentPathForRecursiveRef(documentPath, resolved.Ref) } } return nil @@ -814,6 +831,7 @@ func (loader *Loader) resolveExampleRef(doc *T, component *ExampleRef, documentP return err } component.Value = resolved.Value + documentPath = loader.documentPathForRecursiveRef(documentPath, resolved.Ref) } } return nil @@ -841,6 +859,7 @@ func (loader *Loader) resolveCallbackRef(doc *T, component *CallbackRef, documen return err } component.Value = resolved.Value + documentPath = loader.documentPathForRecursiveRef(documentPath, resolved.Ref) } } value := component.Value @@ -938,6 +957,7 @@ func (loader *Loader) resolveLinkRef(doc *T, component *LinkRef, documentPath *u return err } component.Value = resolved.Value + documentPath = loader.documentPathForRecursiveRef(documentPath, resolved.Ref) } } return nil diff --git a/openapi3/loader_read_from_uri_func_test.go b/openapi3/loader_read_from_uri_func_test.go index 72d4a95a7..8fee2f4c2 100644 --- a/openapi3/loader_read_from_uri_func_test.go +++ b/openapi3/loader_read_from_uri_func_test.go @@ -20,7 +20,7 @@ func TestLoaderReadFromURIFunc(t *testing.T) { require.NoError(t, err) require.NotNil(t, doc) require.NoError(t, doc.Validate(loader.Context)) - require.Equal(t, "bar", doc.Paths["/foo"].Get.Responses.Get(200).Value.Content.Get("application/json").Schema.Value.Properties["foo"].Value.Properties["bar"].Value.Items.Value.Example) + require.Equal(t, "bar", doc.Paths["/foo"].Get.Responses.Get(200).Value.Content.Get("application/json").Schema.Value.Properties["foo2"].Value.Properties["foo"].Value.Properties["bar"].Value.Example) } type multipleSourceLoaderExample struct { diff --git a/openapi3/loader_recursive_ref_test.go b/openapi3/loader_recursive_ref_test.go index bc1f24b88..bd6590364 100644 --- a/openapi3/loader_recursive_ref_test.go +++ b/openapi3/loader_recursive_ref_test.go @@ -13,5 +13,5 @@ func TestLoaderSupportsRecursiveReference(t *testing.T) { require.NoError(t, err) require.NotNil(t, doc) require.NoError(t, doc.Validate(loader.Context)) - require.Equal(t, "bar", doc.Paths["/foo"].Get.Responses.Get(200).Value.Content.Get("application/json").Schema.Value.Properties["foo"].Value.Properties["bar"].Value.Items.Value.Example) + require.Equal(t, "bar", doc.Paths["/foo"].Get.Responses.Get(200).Value.Content.Get("application/json").Schema.Value.Properties["foo2"].Value.Properties["foo"].Value.Properties["bar"].Value.Example) } diff --git a/openapi3/testdata/load_with_go_embed_test.go b/openapi3/testdata/load_with_go_embed_test.go index a5993dcc8..56b274c9b 100644 --- a/openapi3/testdata/load_with_go_embed_test.go +++ b/openapi3/testdata/load_with_go_embed_test.go @@ -27,6 +27,6 @@ func Example() { panic(err) } - fmt.Println(doc.Paths["/foo"].Get.Responses["200"].Value.Content["application/json"].Schema.Value.Properties["foo"].Value.Properties["bar"].Value.Type) - // Output: array + fmt.Println(doc.Paths["/foo"].Get.Responses["200"].Value.Content["application/json"].Schema.Value.Properties["foo2"].Value.Properties["foo"].Value.Properties["bar"].Value.Type) + // Output: string } diff --git a/openapi3/testdata/recursiveRef/components/Foo.yml b/openapi3/testdata/recursiveRef/components/Foo.yml index 0c0899277..53a233666 100644 --- a/openapi3/testdata/recursiveRef/components/Foo.yml +++ b/openapi3/testdata/recursiveRef/components/Foo.yml @@ -1,6 +1,4 @@ type: object properties: bar: - type: array - items: - $ref: ../openapi.yml#/components/schemas/Bar + $ref: ../openapi.yml#/components/schemas/Bar diff --git a/openapi3/testdata/recursiveRef/components/Foo/Foo2.yml b/openapi3/testdata/recursiveRef/components/Foo/Foo2.yml new file mode 100644 index 000000000..aeac81f48 --- /dev/null +++ b/openapi3/testdata/recursiveRef/components/Foo/Foo2.yml @@ -0,0 +1,4 @@ +type: object +properties: + foo: + $ref: ../../openapi.yml#/components/schemas/Foo diff --git a/openapi3/testdata/recursiveRef/openapi.yml b/openapi3/testdata/recursiveRef/openapi.yml index 5dfcfbf7c..3559c8e85 100644 --- a/openapi3/testdata/recursiveRef/openapi.yml +++ b/openapi3/testdata/recursiveRef/openapi.yml @@ -9,5 +9,7 @@ components: schemas: Foo: $ref: ./components/Foo.yml + Foo2: + $ref: ./components/Foo/Foo2.yml Bar: $ref: ./components/Bar.yml diff --git a/openapi3/testdata/recursiveRef/paths/foo.yml b/openapi3/testdata/recursiveRef/paths/foo.yml index dd6c15d0f..1653c7ac7 100644 --- a/openapi3/testdata/recursiveRef/paths/foo.yml +++ b/openapi3/testdata/recursiveRef/paths/foo.yml @@ -7,5 +7,5 @@ get: schema: type: object properties: - foo: - $ref: ../openapi.yml#/components/schemas/Foo + foo2: + $ref: ../openapi.yml#/components/schemas/Foo2