Skip to content

Commit f9ccdc2

Browse files
committed
Support recursive ref loading
1 parent bdba5d1 commit f9ccdc2

File tree

6 files changed

+64
-1
lines changed

6 files changed

+64
-1
lines changed

openapi3/swagger_loader.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ type SwaggerLoader struct {
4444
visitedSecurityScheme map[*SecurityScheme]struct{}
4545
visitedExample map[*Example]struct{}
4646
visitedLink map[*Link]struct{}
47+
48+
visitedSwaggers map[string]*Swagger
4749
}
4850

4951
// NewSwaggerLoader returns an empty SwaggerLoader
@@ -53,6 +55,7 @@ func NewSwaggerLoader() *SwaggerLoader {
5355

5456
func (swaggerLoader *SwaggerLoader) reset() {
5557
swaggerLoader.visitedFiles = make(map[string]struct{})
58+
swaggerLoader.visitedSwaggers = make(map[string]*Swagger)
5659
}
5760

5861
// LoadSwaggerFromURI loads a spec from a remote URL
@@ -170,11 +173,22 @@ func (swaggerLoader *SwaggerLoader) LoadSwaggerFromDataWithPath(data []byte, pat
170173
}
171174

172175
func (swaggerLoader *SwaggerLoader) loadSwaggerFromDataWithPathInternal(data []byte, path *url.URL) (*Swagger, error) {
176+
visited, ok := swaggerLoader.visitedSwaggers[path.String()]
177+
if ok {
178+
return visited, nil
179+
}
180+
173181
swagger := &Swagger{}
182+
swaggerLoader.visitedSwaggers[path.String()] = swagger
183+
174184
if err := yaml.Unmarshal(data, swagger); err != nil {
175185
return nil, err
176186
}
177-
return swagger, swaggerLoader.ResolveRefsIn(swagger, path)
187+
if err := swaggerLoader.ResolveRefsIn(swagger, path); err != nil {
188+
return nil, err
189+
}
190+
191+
return swagger, nil
178192
}
179193

180194
// ResolveRefsIn expands references if for instance spec was just unmarshalled
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package openapi3
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/require"
7+
)
8+
9+
func TestLoaderSupportsRecursiveReference(t *testing.T) {
10+
loader := NewSwaggerLoader()
11+
loader.IsExternalRefsAllowed = true
12+
doc, err := loader.LoadSwaggerFromFile("testdata/recursiveRef/openapi.yml")
13+
require.NoError(t, err)
14+
require.NotNil(t, doc)
15+
require.NoError(t, doc.Validate(loader.Context))
16+
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)
17+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
type: string
2+
example: bar
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
type: object
2+
properties:
3+
bar:
4+
type: array
5+
items:
6+
$ref: ../openapi.yml#/components/schemas/Bar
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
openapi: "3.0.3"
2+
info:
3+
title: Recursive refs example
4+
version: "1.0"
5+
paths:
6+
/foo:
7+
$ref: ./paths/foo.yml
8+
components:
9+
schemas:
10+
Foo:
11+
$ref: ./components/Foo.yml
12+
Bar:
13+
$ref: ./components/Bar.yml
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
get:
2+
responses:
3+
"200":
4+
description: OK
5+
content:
6+
application/json:
7+
schema:
8+
type: object
9+
properties:
10+
foo:
11+
$ref: ../openapi.yml#/components/schemas/Foo

0 commit comments

Comments
 (0)