Skip to content

Commit

Permalink
openapi3: implement circular reference backtracking (#970)
Browse files Browse the repository at this point in the history
* feat(loader): implement reference back-tracking

* update docs

* address review comments

* update docs and readme

* fix inconsistency

* adjust readme
  • Loading branch information
AnatolyRugalev authored Jun 26, 2024
1 parent 57624b3 commit fe47dca
Show file tree
Hide file tree
Showing 10 changed files with 149 additions and 152 deletions.
2 changes: 0 additions & 2 deletions .github/docs/openapi3.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,6 @@ var (
// ErrSchemaInputInf may be returned when validating a number
ErrSchemaInputInf = errors.New("floating point Inf is not allowed")
)
var CircularReferenceCounter = 3
var CircularReferenceError = "kin-openapi bug found: circular schema reference not handled"
var DefaultReadFromURI = URIMapCache(ReadFromURIs(ReadFromHTTP(http.DefaultClient), ReadFromFile))
DefaultReadFromURI returns a caching ReadFromURIFunc which can read remote
HTTP URIs and local file URIs.
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,9 @@ for _, path := range doc.Paths.InMatchingOrder() {

## CHANGELOG: Sub-v1 breaking API changes

### v0.126.0
* `openapi3.CircularReferenceError` and `openapi3.CircularReferenceCounter` are removed. `openapi3.Loader` now implements reference backtracking, so any kind of circular references should be properly resolved.

### v0.125.0
* The `openapi3filter.ErrFunc` and `openapi3filter.LogFunc` func types now take the validated request's context as first argument.

Expand Down
9 changes: 0 additions & 9 deletions cmd/validate/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,6 @@ import (
"github.com/getkin/kin-openapi/openapi3"
)

var (
defaultCircular = openapi3.CircularReferenceCounter
circular = flag.Int("circular", defaultCircular, "bump this (upper) limit when there's trouble with cyclic schema references")
)

var (
defaultDefaults = true
defaults = flag.Bool("defaults", defaultDefaults, "when false, disables schemas' default field validation")
Expand Down Expand Up @@ -59,7 +54,6 @@ func main() {

switch {
case vd.OpenAPI == "3" || strings.HasPrefix(vd.OpenAPI, "3."):
openapi3.CircularReferenceCounter = *circular
loader := openapi3.NewLoader()
loader.IsExternalRefsAllowed = *ext

Expand Down Expand Up @@ -90,9 +84,6 @@ func main() {

case vd.OpenAPI == "2" || strings.HasPrefix(vd.OpenAPI, "2."),
vd.Swagger == "2" || strings.HasPrefix(vd.Swagger, "2."):
if *circular != defaultCircular {
log.Fatal("Flag --circular is only for OpenAPIv3")
}
if *defaults != defaultDefaults {
log.Fatal("Flag --defaults is only for OpenAPIv3")
}
Expand Down
2 changes: 1 addition & 1 deletion openapi3/issue570_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ import (
func TestIssue570(t *testing.T) {
loader := NewLoader()
_, err := loader.LoadFromFile("testdata/issue570.json")
require.ErrorContains(t, err, CircularReferenceError)
require.NoError(t, err)
}
15 changes: 0 additions & 15 deletions openapi3/issue615_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,6 @@ import (
)

func TestIssue615(t *testing.T) {
{
var old int
old, openapi3.CircularReferenceCounter = openapi3.CircularReferenceCounter, 1
defer func() { openapi3.CircularReferenceCounter = old }()

loader := openapi3.NewLoader()
loader.IsExternalRefsAllowed = true
_, err := loader.LoadFromFile("testdata/recursiveRef/issue615.yml")
require.ErrorContains(t, err, openapi3.CircularReferenceError)
}

var old int
old, openapi3.CircularReferenceCounter = openapi3.CircularReferenceCounter, 4
defer func() { openapi3.CircularReferenceCounter = old }()

loader := openapi3.NewLoader()
loader.IsExternalRefsAllowed = true
doc, err := loader.LoadFromFile("testdata/recursiveRef/issue615.yml")
Expand Down
5 changes: 0 additions & 5 deletions openapi3/issue796_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,6 @@ import (
)

func TestIssue796(t *testing.T) {
var old int
// Need to set CircularReferenceCounter to > 10
old, CircularReferenceCounter = CircularReferenceCounter, 20
defer func() { CircularReferenceCounter = old }()

loader := NewLoader()
doc, err := loader.LoadFromFile("testdata/issue796.yml")
require.NoError(t, err)
Expand Down
14 changes: 14 additions & 0 deletions openapi3/load_cicular_ref_with_external_file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,19 @@ func TestLoadCircularRefFromFile(t *testing.T) {
bar.Value.Properties["foo"] = &openapi3.SchemaRef{Ref: "#/components/schemas/Foo", Value: foo.Value}
foo.Value.Properties["bar"] = &openapi3.SchemaRef{Ref: "#/components/schemas/Bar", Value: bar.Value}

bazNestedRef := &openapi3.SchemaRef{Ref: "./baz.yml#/BazNested"}
array := openapi3.NewArraySchema()
array.Items = bazNestedRef
bazNested := &openapi3.Schema{Properties: map[string]*openapi3.SchemaRef{
"bazArray": {
Value: &openapi3.Schema{
Items: bazNestedRef,
},
},
"baz": bazNestedRef,
}}
bazNestedRef.Value = bazNested

want := &openapi3.T{
OpenAPI: "3.0.3",
Info: &openapi3.Info{
Expand All @@ -57,6 +70,7 @@ func TestLoadCircularRefFromFile(t *testing.T) {
Schemas: openapi3.Schemas{
"Foo": foo,
"Bar": bar,
"Baz": bazNestedRef,
},
},
}
Expand Down
Loading

0 comments on commit fe47dca

Please sign in to comment.