From c32f7722d82ba1db279e624828a777698983a889 Mon Sep 17 00:00:00 2001 From: Anton Tolokan Date: Tue, 8 Nov 2022 17:38:28 +0300 Subject: [PATCH 1/2] Fixed recurive reference resolving when property referencies local component schema type, which referencies json schema in another dir, in which property referencies another json in some non-root (not in the same dir as the specification with local reference) dir json schema --- openapi3/loader.go | 4 ++ openapi3/loader_test.go | 23 ++++++++++ .../testdata/refInLocalRef/messages/data.json | 12 +++++ .../refInLocalRef/messages/dataPart.json | 9 ++++ .../refInLocalRef/messages/definitions.json | 7 +++ .../refInLocalRef/messages/request.json | 11 +++++ .../refInLocalRef/messages/response.json | 9 ++++ openapi3/testdata/refInLocalRef/openapi.json | 46 +++++++++++++++++++ .../messages/data.json | 12 +++++ .../messages/dataPart.json | 9 ++++ .../messages/definitions.json | 7 +++ .../messages/request.json | 11 +++++ .../messages/response.json | 9 ++++ .../spec/openapi.json | 46 +++++++++++++++++++ 14 files changed, 215 insertions(+) create mode 100644 openapi3/testdata/refInLocalRef/messages/data.json create mode 100644 openapi3/testdata/refInLocalRef/messages/dataPart.json create mode 100644 openapi3/testdata/refInLocalRef/messages/definitions.json create mode 100644 openapi3/testdata/refInLocalRef/messages/request.json create mode 100644 openapi3/testdata/refInLocalRef/messages/response.json create mode 100644 openapi3/testdata/refInLocalRef/openapi.json create mode 100644 openapi3/testdata/refInLocalRefInParentsSubdir/messages/data.json create mode 100644 openapi3/testdata/refInLocalRefInParentsSubdir/messages/dataPart.json create mode 100644 openapi3/testdata/refInLocalRefInParentsSubdir/messages/definitions.json create mode 100644 openapi3/testdata/refInLocalRefInParentsSubdir/messages/request.json create mode 100644 openapi3/testdata/refInLocalRefInParentsSubdir/messages/response.json create mode 100644 openapi3/testdata/refInLocalRefInParentsSubdir/spec/openapi.json diff --git a/openapi3/loader.go b/openapi3/loader.go index 1ab693b0f..cb8ee998b 100644 --- a/openapi3/loader.go +++ b/openapi3/loader.go @@ -745,6 +745,10 @@ func (loader *Loader) resolveSchemaRef(doc *T, component *SchemaRef, documentPat foundPath := loader.getResolvedRefPath(ref, &resolved, documentPath, componentPath) documentPath = loader.documentPathForRecursiveRef(documentPath, foundPath) } + if loader.visitedSchema == nil { + loader.visitedSchema = make(map[*Schema]struct{}) + } + loader.visitedSchema[component.Value] = struct{}{} } value := component.Value if value == nil { diff --git a/openapi3/loader_test.go b/openapi3/loader_test.go index 684e1b44d..e792767fd 100644 --- a/openapi3/loader_test.go +++ b/openapi3/loader_test.go @@ -263,6 +263,29 @@ func TestLoadWithReferenceInReference(t *testing.T) { require.Equal(t, "string", doc.Paths["/api/test/ref/in/ref"].Post.RequestBody.Value.Content["application/json"].Schema.Value.Properties["definition_reference"].Value.Type) } +func TestLoadWithRecursiveReferenceInLocalReferenceInParentSubdir(t *testing.T) { + loader := NewLoader() + loader.IsExternalRefsAllowed = true + doc, err := loader.LoadFromFile("testdata/refInLocalRefInParentsSubdir/spec/openapi.json") + require.NoError(t, err) + require.NotNil(t, doc) + err = doc.Validate(loader.Context) + require.NoError(t, err) + require.Equal(t, "object", doc.Paths["/api/test/ref/in/ref"].Post.RequestBody.Value.Content["application/json"].Schema.Value.Properties["definition_reference"].Value.Type) +} + +func TestLoadWithRecursiveReferenceInRefrerenceInLocalReference(t *testing.T) { + loader := NewLoader() + loader.IsExternalRefsAllowed = true + doc, err := loader.LoadFromFile("testdata/refInLocalRef/openapi.json") + require.NoError(t, err) + require.NotNil(t, doc) + err = doc.Validate(loader.Context) + require.NoError(t, err) + require.Equal(t, "integer", doc.Paths["/api/test/ref/in/ref"].Post.RequestBody.Value.Content["application/json"].Schema.Value.Properties["data"].Value.Properties["definition_reference"].Value.Properties["ref_prop_part"].Value.Properties["idPart"].Value.Type) + require.Equal(t, "int64", doc.Paths["/api/test/ref/in/ref"].Post.RequestBody.Value.Content["application/json"].Schema.Value.Properties["data"].Value.Properties["definition_reference"].Value.Properties["ref_prop_part"].Value.Properties["idPart"].Value.Format) +} + func TestLoadWithReferenceInReferenceInProperty(t *testing.T) { loader := NewLoader() loader.IsExternalRefsAllowed = true diff --git a/openapi3/testdata/refInLocalRef/messages/data.json b/openapi3/testdata/refInLocalRef/messages/data.json new file mode 100644 index 000000000..cfdc18efb --- /dev/null +++ b/openapi3/testdata/refInLocalRef/messages/data.json @@ -0,0 +1,12 @@ +{ + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "ref_prop_part": { + "$ref": "./dataPart.json" + } + } +} diff --git a/openapi3/testdata/refInLocalRef/messages/dataPart.json b/openapi3/testdata/refInLocalRef/messages/dataPart.json new file mode 100644 index 000000000..9ecb5850a --- /dev/null +++ b/openapi3/testdata/refInLocalRef/messages/dataPart.json @@ -0,0 +1,9 @@ +{ + "type": "object", + "properties": { + "idPart": { + "type": "integer", + "format": "int64" + } + } +} diff --git a/openapi3/testdata/refInLocalRef/messages/definitions.json b/openapi3/testdata/refInLocalRef/messages/definitions.json new file mode 100644 index 000000000..78b942836 --- /dev/null +++ b/openapi3/testdata/refInLocalRef/messages/definitions.json @@ -0,0 +1,7 @@ +{ + "definitions": { + "External": { + "type": "string" + } + } +} diff --git a/openapi3/testdata/refInLocalRef/messages/request.json b/openapi3/testdata/refInLocalRef/messages/request.json new file mode 100644 index 000000000..7225ff190 --- /dev/null +++ b/openapi3/testdata/refInLocalRef/messages/request.json @@ -0,0 +1,11 @@ +{ + "type": "object", + "required": [ + "definition_reference" + ], + "properties": { + "definition_reference": { + "$ref": "./data.json" + } + } +} diff --git a/openapi3/testdata/refInLocalRef/messages/response.json b/openapi3/testdata/refInLocalRef/messages/response.json new file mode 100644 index 000000000..b636f528b --- /dev/null +++ b/openapi3/testdata/refInLocalRef/messages/response.json @@ -0,0 +1,9 @@ +{ + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + } + } +} diff --git a/openapi3/testdata/refInLocalRef/openapi.json b/openapi3/testdata/refInLocalRef/openapi.json new file mode 100644 index 000000000..f0c9915c7 --- /dev/null +++ b/openapi3/testdata/refInLocalRef/openapi.json @@ -0,0 +1,46 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "Reference in reference example", + "version": "1.0.0" + }, + "paths": { + "/api/test/ref/in/ref": { + "post": { + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties" : { + "data": { + "$ref": "#/components/schemas/Request" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "$ref": "messages/response.json" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "Request": { + "$ref": "messages/request.json" + } + } + } +} diff --git a/openapi3/testdata/refInLocalRefInParentsSubdir/messages/data.json b/openapi3/testdata/refInLocalRefInParentsSubdir/messages/data.json new file mode 100644 index 000000000..cfdc18efb --- /dev/null +++ b/openapi3/testdata/refInLocalRefInParentsSubdir/messages/data.json @@ -0,0 +1,12 @@ +{ + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "ref_prop_part": { + "$ref": "./dataPart.json" + } + } +} diff --git a/openapi3/testdata/refInLocalRefInParentsSubdir/messages/dataPart.json b/openapi3/testdata/refInLocalRefInParentsSubdir/messages/dataPart.json new file mode 100644 index 000000000..9ecb5850a --- /dev/null +++ b/openapi3/testdata/refInLocalRefInParentsSubdir/messages/dataPart.json @@ -0,0 +1,9 @@ +{ + "type": "object", + "properties": { + "idPart": { + "type": "integer", + "format": "int64" + } + } +} diff --git a/openapi3/testdata/refInLocalRefInParentsSubdir/messages/definitions.json b/openapi3/testdata/refInLocalRefInParentsSubdir/messages/definitions.json new file mode 100644 index 000000000..78b942836 --- /dev/null +++ b/openapi3/testdata/refInLocalRefInParentsSubdir/messages/definitions.json @@ -0,0 +1,7 @@ +{ + "definitions": { + "External": { + "type": "string" + } + } +} diff --git a/openapi3/testdata/refInLocalRefInParentsSubdir/messages/request.json b/openapi3/testdata/refInLocalRefInParentsSubdir/messages/request.json new file mode 100644 index 000000000..7225ff190 --- /dev/null +++ b/openapi3/testdata/refInLocalRefInParentsSubdir/messages/request.json @@ -0,0 +1,11 @@ +{ + "type": "object", + "required": [ + "definition_reference" + ], + "properties": { + "definition_reference": { + "$ref": "./data.json" + } + } +} diff --git a/openapi3/testdata/refInLocalRefInParentsSubdir/messages/response.json b/openapi3/testdata/refInLocalRefInParentsSubdir/messages/response.json new file mode 100644 index 000000000..b636f528b --- /dev/null +++ b/openapi3/testdata/refInLocalRefInParentsSubdir/messages/response.json @@ -0,0 +1,9 @@ +{ + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + } + } +} diff --git a/openapi3/testdata/refInLocalRefInParentsSubdir/spec/openapi.json b/openapi3/testdata/refInLocalRefInParentsSubdir/spec/openapi.json new file mode 100644 index 000000000..0bf9bd36e --- /dev/null +++ b/openapi3/testdata/refInLocalRefInParentsSubdir/spec/openapi.json @@ -0,0 +1,46 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "Reference in reference example", + "version": "1.0.0" + }, + "paths": { + "/api/test/ref/in/ref": { + "post": { + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "../messages/request.json" + } + } + } + }, + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "ref_prop": { + "$ref": "#/components/schemas/Data" + } + } + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "Data": { + "$ref": "../messages/data.json" + } + } + } +} From c0be90b6a882618f4856d1e4a1b4ed42b6c9d57e Mon Sep 17 00:00:00 2001 From: Anton Tolokan Date: Tue, 8 Nov 2022 20:40:04 +0300 Subject: [PATCH 2/2] Removed unnecessary testdata files --- openapi3/testdata/refInLocalRef/messages/definitions.json | 7 ------- .../refInLocalRefInParentsSubdir/messages/definitions.json | 7 ------- 2 files changed, 14 deletions(-) delete mode 100644 openapi3/testdata/refInLocalRef/messages/definitions.json delete mode 100644 openapi3/testdata/refInLocalRefInParentsSubdir/messages/definitions.json diff --git a/openapi3/testdata/refInLocalRef/messages/definitions.json b/openapi3/testdata/refInLocalRef/messages/definitions.json deleted file mode 100644 index 78b942836..000000000 --- a/openapi3/testdata/refInLocalRef/messages/definitions.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "definitions": { - "External": { - "type": "string" - } - } -} diff --git a/openapi3/testdata/refInLocalRefInParentsSubdir/messages/definitions.json b/openapi3/testdata/refInLocalRefInParentsSubdir/messages/definitions.json deleted file mode 100644 index 78b942836..000000000 --- a/openapi3/testdata/refInLocalRefInParentsSubdir/messages/definitions.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "definitions": { - "External": { - "type": "string" - } - } -}