From 789113dfcc39e3720e97375bc40785520834f251 Mon Sep 17 00:00:00 2001 From: dominicqi Date: Thu, 17 Nov 2022 11:34:16 +0800 Subject: [PATCH 1/3] fix: example ref to schemas cause error --- openapi3/loader.go | 18 + openapi3/loader_exmaple_schema_ref_test.go | 17 + openapi3/testdata/example-schemas-ref.json | 414 +++++++++++++++++++++ 3 files changed, 449 insertions(+) create mode 100644 openapi3/loader_exmaple_schema_ref_test.go create mode 100644 openapi3/testdata/example-schemas-ref.json diff --git a/openapi3/loader.go b/openapi3/loader.go index 138431fc0..a02d0339a 100644 --- a/openapi3/loader.go +++ b/openapi3/loader.go @@ -683,6 +683,24 @@ func (loader *Loader) resolveResponseRef(doc *T, component *ResponseRef, documen sort.Strings(examples) for _, name := range examples { example := contentType.Examples[name] + if exampleRef := example.Ref; exampleRef != "" { + parse, err := url.Parse(exampleRef) + if err != nil { + return err + } + if refType := strings.Split(parse.Fragment[1:], "/")[1]; refType == "schemas" { + var resolved SchemaRef + _, err := loader.resolveComponent(doc, exampleRef, parse, &resolved) + if err != nil { + return err + } + contentType.Examples[name] = &ExampleRef{ + Ref: exampleRef, + Value: NewExample(resolved.Value), + } + continue + } + } if err := loader.resolveExampleRef(doc, example, documentPath); err != nil { return err } diff --git a/openapi3/loader_exmaple_schema_ref_test.go b/openapi3/loader_exmaple_schema_ref_test.go new file mode 100644 index 000000000..dc18e25dd --- /dev/null +++ b/openapi3/loader_exmaple_schema_ref_test.go @@ -0,0 +1,17 @@ +package openapi3 + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestLoadSpecWithExampleRefToSchemas(t *testing.T) { + loader := NewLoader() + loader.IsExternalRefsAllowed = true + api, err := loader.LoadFromFile("testdata/example-schemas-ref.json") + exampleValue := api.Paths["/pet"].Put.Responses.Get(400).Value.Content.Get("*/*").Examples["200"].Value.Value + schemaRef := api.Components.Schemas["Pet"].Value + require.Equal(t, exampleValue, schemaRef) + require.NoError(t, err) +} diff --git a/openapi3/testdata/example-schemas-ref.json b/openapi3/testdata/example-schemas-ref.json new file mode 100644 index 000000000..07e8924d0 --- /dev/null +++ b/openapi3/testdata/example-schemas-ref.json @@ -0,0 +1,414 @@ +{ + "openapi": "3.0.2", + "info": { + "title": "Swagger Petstore - OpenAPI 3.0", + "description": "This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about\nSwagger at [http://swagger.io](http://swagger.io). In the third iteration of the pet store, we've switched to the design first approach!\nYou can now help us improve the API whether it's by making changes to the definition itself or to the code.\nThat way, with time, we can improve the API in general, and expose some of the new features in OAS3.\n\nSome useful links:\n- [The Pet Store repository](https://github.com/swagger-api/swagger-petstore)\n- [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml)", + "termsOfService": "http://swagger.io/terms/", + "contact": { + "email": "apiteam@swagger.io" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + }, + "version": "1.0.17" + }, + "externalDocs": { + "description": "Find out more about Swagger", + "url": "http://swagger.io" + }, + "servers": [ + { + "url": "/api/v3" + } + ], + "tags": [ + { + "name": "pet", + "description": "Everything about your Pets", + "externalDocs": { + "description": "Find out more", + "url": "http://swagger.io" + } + }, + { + "name": "store", + "description": "Access to Petstore orders", + "externalDocs": { + "description": "Find out more about our store", + "url": "http://swagger.io" + } + }, + { + "name": "user", + "description": "Operations about user" + } + ], + "paths": { + "/pet": { + "put": { + "tags": [ + "pet" + ], + "summary": "Update an existing pet", + "description": "Update an existing pet by Id", + "operationId": "updatePet", + "requestBody": { + "description": "Update an existent pet in the store", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + } + } + }, + "400": { + "description": "Invalid ID supplied", + "content": { + "*/*": { + "examples": { + "200": { + "$ref": "#/components/schemas/Pet" + } + } + } + } + }, + "404": { + "description": "Pet not found" + }, + "405": { + "description": "Validation exception" + } + }, + "security": [ + { + "petstore_auth": [ + "write:pets", + "read:pets" + ] + } + ] + } + } + }, + "components": { + "schemas": { + "Order": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64", + "example": 10 + }, + "petId": { + "type": "integer", + "format": "int64", + "example": 198772 + }, + "quantity": { + "type": "integer", + "format": "int32", + "example": 7 + }, + "shipDate": { + "type": "string", + "format": "date-time" + }, + "status": { + "type": "string", + "description": "Order Status", + "example": "approved", + "enum": [ + "placed", + "approved", + "delivered" + ] + }, + "complete": { + "type": "boolean" + } + }, + "xml": { + "name": "order" + } + }, + "Customer": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64", + "example": 100000 + }, + "username": { + "type": "string", + "example": "fehguy" + }, + "address": { + "type": "array", + "xml": { + "name": "addresses", + "wrapped": true + }, + "items": { + "$ref": "#/components/schemas/Address" + } + } + }, + "xml": { + "name": "customer" + } + }, + "Address": { + "type": "object", + "properties": { + "street": { + "type": "string", + "example": "437 Lytton" + }, + "city": { + "type": "string", + "example": "Palo Alto" + }, + "state": { + "type": "string", + "example": "CA" + }, + "zip": { + "type": "string", + "example": "94301" + } + }, + "xml": { + "name": "address" + } + }, + "Category": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64", + "example": 1 + }, + "name": { + "type": "string", + "example": "Dogs" + } + }, + "xml": { + "name": "category" + } + }, + "User": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64", + "example": 10 + }, + "username": { + "type": "string", + "example": "theUser" + }, + "firstName": { + "type": "string", + "example": "John" + }, + "lastName": { + "type": "string", + "example": "James" + }, + "email": { + "type": "string", + "example": "john@email.com" + }, + "password": { + "type": "string", + "example": "12345" + }, + "phone": { + "type": "string", + "example": "12345" + }, + "userStatus": { + "type": "integer", + "description": "User Status", + "format": "int32", + "example": 1 + } + }, + "xml": { + "name": "user" + } + }, + "Tag": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + } + }, + "xml": { + "name": "tag" + } + }, + "Pet": { + "required": [ + "name", + "photoUrls" + ], + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64", + "example": 10 + }, + "name": { + "type": "string", + "example": "doggie" + }, + "category": { + "$ref": "#/components/schemas/Category" + }, + "photoUrls": { + "type": "array", + "xml": { + "wrapped": true + }, + "items": { + "type": "string", + "xml": { + "name": "photoUrl" + } + } + }, + "tags": { + "type": "array", + "xml": { + "wrapped": true + }, + "items": { + "$ref": "#/components/schemas/Tag" + } + }, + "status": { + "type": "string", + "description": "pet status in the store", + "enum": [ + "available", + "pending", + "sold" + ] + } + }, + "xml": { + "name": "pet" + } + }, + "ApiResponse": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "type": { + "type": "string" + }, + "message": { + "type": "string" + } + }, + "xml": { + "name": "##default" + } + } + }, + "requestBodies": { + "Pet": { + "description": "Pet object that needs to be added to the store", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Pet" + } + } + } + }, + "UserArray": { + "description": "List of user object", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/User" + } + } + } + } + } + }, + "securitySchemes": { + "petstore_auth": { + "type": "oauth2", + "flows": { + "implicit": { + "authorizationUrl": "https://petstore3.swagger.io/oauth/authorize", + "scopes": { + "write:pets": "modify pets in your account", + "read:pets": "read your pets" + } + } + } + }, + "api_key": { + "type": "apiKey", + "name": "api_key", + "in": "header" + } + } + } +} From 5d74c2df9ed6a1be69527dbf7092fcf79787d038 Mon Sep 17 00:00:00 2001 From: dominicqi Date: Mon, 28 Nov 2022 11:52:15 +0800 Subject: [PATCH 2/3] fix: example ref to schemas cause error unit test --- openapi3/loader_exmaple_schema_ref_test.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/openapi3/loader_exmaple_schema_ref_test.go b/openapi3/loader_exmaple_schema_ref_test.go index dc18e25dd..df9eb6643 100644 --- a/openapi3/loader_exmaple_schema_ref_test.go +++ b/openapi3/loader_exmaple_schema_ref_test.go @@ -8,10 +8,13 @@ import ( func TestLoadSpecWithExampleRefToSchemas(t *testing.T) { loader := NewLoader() - loader.IsExternalRefsAllowed = true - api, err := loader.LoadFromFile("testdata/example-schemas-ref.json") - exampleValue := api.Paths["/pet"].Put.Responses.Get(400).Value.Content.Get("*/*").Examples["200"].Value.Value - schemaRef := api.Components.Schemas["Pet"].Value + doc, err := loader.LoadFromFile("testdata/example-schemas-ref.json") + require.NoError(t, err) + + err = doc.Validate(loader.Context) + require.NoError(t, err) + exampleValue := doc.Paths["/pet"].Put.Responses.Get(400).Value.Content.Get("*/*").Examples["200"].Value.Value + schemaRef := doc.Components.Schemas["Pet"].Value require.Equal(t, exampleValue, schemaRef) require.NoError(t, err) } From ecfb1a5881797aea36171b82f0ba8bd8877103c8 Mon Sep 17 00:00:00 2001 From: dominicqi Date: Mon, 28 Nov 2022 13:54:54 +0800 Subject: [PATCH 3/3] fix: example ref to schemas cause error unit test error --- openapi3/loader.go | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/openapi3/loader.go b/openapi3/loader.go index a02d0339a..e06c2829e 100644 --- a/openapi3/loader.go +++ b/openapi3/loader.go @@ -683,23 +683,22 @@ func (loader *Loader) resolveResponseRef(doc *T, component *ResponseRef, documen sort.Strings(examples) for _, name := range examples { example := contentType.Examples[name] - if exampleRef := example.Ref; exampleRef != "" { - parse, err := url.Parse(exampleRef) + if exampleRef := example.Ref; strings.HasPrefix(exampleRef, "#/components/schemas") { + parsedUrl, err := url.Parse(exampleRef) if err != nil { return err } - if refType := strings.Split(parse.Fragment[1:], "/")[1]; refType == "schemas" { - var resolved SchemaRef - _, err := loader.resolveComponent(doc, exampleRef, parse, &resolved) - if err != nil { - return err - } - contentType.Examples[name] = &ExampleRef{ - Ref: exampleRef, - Value: NewExample(resolved.Value), - } - continue + var resolved SchemaRef + _, err = loader.resolveComponent(doc, exampleRef, parsedUrl, &resolved) + if err != nil { + return err + } + contentType.Examples[name] = &ExampleRef{ + Ref: exampleRef, + Value: NewExample(resolved.Value), } + continue + } if err := loader.resolveExampleRef(doc, example, documentPath); err != nil { return err