Repository: getkin/kin-openapi
Pull request #57 (2019-01-17 06:42:29)

Add resolve Content in Query


Patch:
diff --git a/openapi2/openapi2.go b/openapi2/openapi2.go
index 231f3c9..3fdd8a1 100644
--- a/openapi2/openapi2.go
+++ b/openapi2/openapi2.go
@@ -16,7 +16,7 @@ import (
 type Swagger struct {
 	Info                openapi3.Info                  `json:"info"`
 	ExternalDocs        *openapi3.ExternalDocs         `json:"externalDocs,omitempty"`
-	Schemes             []string                       `json:"schemas,omitempty"`
+	Schemes             []string                       `json:"schemes,omitempty"`
 	Host                string                         `json:"host,omitempty"`
 	BasePath            string                         `json:"basePath,omitempty"`
 	Paths               map[string]*PathItem           `json:"paths,omitempty"`
diff --git a/openapi3/parameter.go b/openapi3/parameter.go
index 63d30f9..5d6d6f3 100644
--- a/openapi3/parameter.go
+++ b/openapi3/parameter.go
@@ -144,6 +144,10 @@ func (parameter *Parameter) Validate(c context.Context) error {
 	default:
 		return fmt.Errorf("Parameter can't have 'in' value '%s'", parameter.In)
 	}
+	if parameter.Schema != nil && parameter.Content != nil {
+		return fmt.Errorf("Parameter '%v' schema is invalid: %v", parameter.Name,
+			errors.New("Cannot contain both schema and content in a parameter"))
+	}
 	if schema := parameter.Schema; schema != nil {
 		if err := schema.Validate(c); err != nil {
 			return fmt.Errorf("Parameter '%v' schema is invalid: %v", parameter.Name, err)
diff --git a/openapi3/swagger_loader.go b/openapi3/swagger_loader.go
index 9555c20..375d30b 100644
--- a/openapi3/swagger_loader.go
+++ b/openapi3/swagger_loader.go
@@ -3,6 +3,7 @@ package openapi3
 import (
 	"context"
 	"encoding/json"
+	"errors"
 	"fmt"
 	"io/ioutil"
 	"net/http"
@@ -319,6 +320,16 @@ func (swaggerLoader *SwaggerLoader) resolveParameterRef(swagger *Swagger, compon
 	if value == nil {
 		return nil
 	}
+	if value.Content != nil && value.Schema != nil {
+		return errors.New("Cannot contain both schema and content in a parameter")
+	}
+	for _, contentType := range value.Content {
+		if schema := contentType.Schema; schema != nil {
+			if err := swaggerLoader.resolveSchemaRef(swagger, schema, path); err != nil {
+				return err
+			}
+		}
+	}
 	if schema := value.Schema; schema != nil {
 		if err := swaggerLoader.resolveSchemaRef(swagger, schema, path); err != nil {
 			return err


Test patch:
diff --git a/openapi2conv/openapi2_conv_test.go b/openapi2conv/openapi2_conv_test.go
index 81fc176..1265792 100644
--- a/openapi2conv/openapi2_conv_test.go
+++ b/openapi2conv/openapi2_conv_test.go
@@ -37,7 +37,7 @@ func TestConvOpenAPIV2ToV3(t *testing.T) {
 const exampleV2 = `
 {
   "info": {},
-  "schemas": ["https"],
+  "schemes": ["https"],
   "host": "test.example.com",
   "basePath": "/v2",
   "paths": {
diff --git a/openapi3/swagger_loader_relative_refs_test.go b/openapi3/swagger_loader_relative_refs_test.go
index 74e1ae0..9b3a6f9 100644
--- a/openapi3/swagger_loader_relative_refs_test.go
+++ b/openapi3/swagger_loader_relative_refs_test.go
@@ -16,6 +16,13 @@ type refTestDataEntry struct {
 	testFunc        func(t *testing.T, swagger *openapi3.Swagger)
 }
 
+type refTestDataEntryWithErrorMessage struct {
+	name            string
+	contentTemplate string
+	errorMessage    *string
+	testFunc        func(t *testing.T, swagger *openapi3.Swagger)
+}
+
 var refTestDataEntries = []refTestDataEntry{
 	{
 		name:            "SchemaRef",
@@ -113,6 +120,17 @@ var refTestDataEntries = []refTestDataEntry{
 			require.Equal(t, "id", swagger.Paths["/test/{id}"].Get.Parameters[0].Value.Name)
 		},
 	},
+
+	{
+		name:            "PathOperationParameterRefWithContentInQuery",
+		contentTemplate: externalPathOperationParameterWithContentInQueryTemplate,
+		testFunc: func(t *testing.T, swagger *openapi3.Swagger) {
+			schemaRef := swagger.Paths["/test/{id}"].Get.Parameters[0].Value.Content["application/json"].Schema
+			require.NotNil(t, schemaRef.Value)
+			require.Equal(t, "string", schemaRef.Value.Type)
+		},
+	},
+
 	{
 		name:            "PathOperationRequestBodyExampleRef",
 		contentTemplate: externalPathOperationRequestBodyExampleRefTemplate,
@@ -165,6 +183,16 @@ var refTestDataEntries = []refTestDataEntry{
 	},
 }
 
+var refTestDataEntriesResponseError = []refTestDataEntryWithErrorMessage{
+	{
+		name:            "CannotContainBothSchemaAndContentInAParameter",
+		contentTemplate: externalCannotContainBothSchemaAndContentInAParameter,
+		errorMessage:    &(&struct{ x string }{"Cannot contain both schema and content in a parameter"}).x,
+		testFunc: func(t *testing.T, swagger *openapi3.Swagger) {
+		},
+	},
+}
+
 func TestLoadFromDataWithExternalRef(t *testing.T) {
 	for _, td := range refTestDataEntries {
 		t.Logf("testcase '%s'", td.name)
@@ -178,6 +206,19 @@ func TestLoadFromDataWithExternalRef(t *testing.T) {
 	}
 }
 
+func TestLoadFromDataWithExternalRefResponseError(t *testing.T) {
+	for _, td := range refTestDataEntriesResponseError {
+		t.Logf("testcase '%s'", td.name)
+
+		spec := []byte(fmt.Sprintf(td.contentTemplate, "components.openapi.json"))
+		loader := openapi3.NewSwaggerLoader()
+		loader.IsExternalRefsAllowed = true
+		swagger, err := loader.LoadSwaggerFromDataWithPath(spec, &url.URL{Path: "testdata/testfilename.openapi.json"})
+		require.EqualError(t, err, *td.errorMessage)
+		td.testFunc(t, swagger)
+	}
+}
+
 func TestLoadFromDataWithExternalNestedRef(t *testing.T) {
 	for _, td := range refTestDataEntries {
 		t.Logf("testcase '%s'", td.name)
@@ -420,6 +461,77 @@ const externalPathOperationParameterSchemaRefTemplate = `
     }
 }`
 
+const externalPathOperationParameterWithContentInQueryTemplate = `
+{
+    "openapi": "3.0.0",
+    "info": {
+        "title": "",
+        "version": "1"
+    },
+    "paths": {
+        "/test/{id}": {
+            "get": {
+                "responses": {},
+                "parameters": [
+                    {
+                        "$ref": "#/components/parameters/CustomTestParameter"
+                    }
+                ]
+            }
+        }
+    },
+    "components": {
+        "parameters": {
+            "CustomTestParameter": {
+                "content": {
+                    "application/json": {
+                        "schema": {
+                            "$ref": "%s#/components/schemas/CustomTestSchema"
+                        }
+                    }
+                }
+            }
+        }
+    }
+}`
+
+const externalCannotContainBothSchemaAndContentInAParameter = `
+{
+    "openapi": "3.0.0",
+    "info": {
+        "title": "",
+        "version": "1"
+    },
+    "paths": {
+        "/test/{id}": {
+            "get": {
+                "responses": {},
+                "parameters": [
+                    {
+                        "$ref": "#/components/parameters/CustomTestParameter"
+                    }
+                ]
+            }
+        }
+    },
+    "components": {
+        "parameters": {
+            "CustomTestParameter": {
+                "content": {
+                    "application/json": {
+                        "schema": {
+                            "$ref": "%s#/components/schemas/CustomTestSchema"
+                        }
+                    }
+                },
+                "schema": {
+                    "$ref": "%s#/components/schemas/CustomTestSchema"
+                }
+            }
+        }
+    }
+}`
+
 const externalPathOperationRequestBodyExampleRefTemplate = `
 {
     "openapi": "3.0.0",