Skip to content

Commit

Permalink
Fix handling recursive refs (#403)
Browse files Browse the repository at this point in the history
  • Loading branch information
stakme authored Aug 14, 2021
1 parent 4a3eb86 commit 9b79d5d
Show file tree
Hide file tree
Showing 8 changed files with 33 additions and 9 deletions.
20 changes: 20 additions & 0 deletions openapi3/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ type Loader struct {

Context context.Context

rootDir string

visitedPathItemRefs map[string]struct{}

visitedDocuments map[string]*T
Expand Down Expand Up @@ -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)})
}

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion openapi3/loader_read_from_uri_func_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion openapi3/loader_recursive_ref_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
4 changes: 2 additions & 2 deletions openapi3/testdata/load_with_go_embed_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
4 changes: 1 addition & 3 deletions openapi3/testdata/recursiveRef/components/Foo.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
type: object
properties:
bar:
type: array
items:
$ref: ../openapi.yml#/components/schemas/Bar
$ref: ../openapi.yml#/components/schemas/Bar
4 changes: 4 additions & 0 deletions openapi3/testdata/recursiveRef/components/Foo/Foo2.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
type: object
properties:
foo:
$ref: ../../openapi.yml#/components/schemas/Foo
2 changes: 2 additions & 0 deletions openapi3/testdata/recursiveRef/openapi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,7 @@ components:
schemas:
Foo:
$ref: ./components/Foo.yml
Foo2:
$ref: ./components/Foo/Foo2.yml
Bar:
$ref: ./components/Bar.yml
4 changes: 2 additions & 2 deletions openapi3/testdata/recursiveRef/paths/foo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ get:
schema:
type: object
properties:
foo:
$ref: ../openapi.yml#/components/schemas/Foo
foo2:
$ref: ../openapi.yml#/components/schemas/Foo2

0 comments on commit 9b79d5d

Please sign in to comment.