Repository: deepmap/oapi-codegen (go)

Issue:
External URL ref and oneOf broken generated code
### Version
master (SHA fec990c8f82)

### Config
```
package: openapi
generate:
  gorilla-server: true
  client: true
  models: true
output: pkg/openapi/generated.go
import-mapping:
  'https://raw.githubusercontent.com/deepmap/oapi-codegen/master/examples/petstore-expanded/petstore-expanded.yaml': github.com/deepmap/oapi-codegen/examples/petstore-expanded
```

### Spec 
```
openapi: "3.0.0"
info:
  version: 1.0.0
  title: Example broken generation with oneOf and external remote ref
paths:
  /check:
    get:
      summary: Return broken example
      responses:
        '200':
          description: Ok
          content:
            application/json:
              schema:
                items:
                  $ref: '#/components/schemas/exampleSchema'
components:
  schemas:
    exampleSchema:
      properties:
        item:
          type: object
          oneOf:
            - $ref: 'https://raw.githubusercontent.com/deepmap/oapi-codegen/master/examples/petstore-expanded/petstore-expanded.yaml#/components/schemas/NewPet'
      required:
        - item
```

### Problems

#### Running command `oapi-codegen --config config.yaml spec.yaml` failed with error 

Error `openapi.go:61:51: expected '(', found '.' (and 2 more errors)`

If watch output, we'll see broken generated methods `As/From/Merge` for `exampleSchema.item`: generator put union type name as is with dot in name `externalRef\d+.SchemaName`: 
```
// AsexternalRef0.NewPet returns the union data inside the ExampleSchema_Item as a externalRef0.NewPet
        func (t ExampleSchema_Item) AsexternalRef0.NewPet() (externalRef0.NewPet, error) {
            var body externalRef0.NewPet
            err := json.Unmarshal(t.union, &body)
            return body, err
        }

        // FromexternalRef0.NewPet overwrites any union data inside the ExampleSchema_Item as the provided externalRef0.NewPet
        func (t *ExampleSchema_Item) FromexternalRef0.NewPet (v externalRef0.NewPet) error {
            b, err := json.Marshal(v)
            t.union = b
            return err
        }

        // MergeexternalRef0.NewPet performs a merge with any union data inside the ExampleSchema_Item, using the provided externalRef0.NewPet
        func (t *ExampleSchema_Item) MergeexternalRef0.NewPet (v externalRef0.NewPet) error {
            b, err := json.Marshal(v)
            if err != nil {
              return err
            }

            merged, err := runtime.JsonMerge(b, t.union)
            t.union = merged
            return err
        }
```

#### Generated code with enabled gorilla-server does not generate import gorilla/mux

This just can be fixed by adding 
```
additional-imports:
  - package: github.com/gorilla/mux
```

But... seems like it must be automatically added by enabling gorilla generator.

Pull request description:
Fixed #719: fix generate for union methods.
Fix #719 

Patch:
diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go
index 7d03752..308d1cd 100644
--- a/pkg/codegen/codegen.go
+++ b/pkg/codegen/codegen.go
@@ -138,8 +138,12 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) {
 		return "", fmt.Errorf("error creating operation definitions: %w", err)
 	}
 
+	xGoTypeImports, err := OperationImports(ops)
+	if err != nil {
+		return "", fmt.Errorf("error getting operation imports: %w", err)
+	}
+
 	var typeDefinitions, constantDefinitions string
-	var xGoTypeImports map[string]goImport
 	if opts.Generate.Models {
 		typeDefinitions, err = GenerateTypeDefinitions(t, spec, ops, opts.OutputOptions.ExcludeSchemas)
 		if err != nil {
@@ -151,10 +155,11 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) {
 			return "", fmt.Errorf("error generating constants: %w", err)
 		}
 
-		xGoTypeImports, err = GetTypeDefinitionsImports(spec, opts.OutputOptions.ExcludeSchemas)
+		imprts, err := GetTypeDefinitionsImports(spec, opts.OutputOptions.ExcludeSchemas)
 		if err != nil {
 			return "", fmt.Errorf("error getting type definition imports: %w", err)
 		}
+		MergeImports(xGoTypeImports, imprts)
 	}
 
 	var echoServerOut string
@@ -794,6 +799,60 @@ func LoadTemplates(src embed.FS, t *template.Template) error {
 	})
 }
 
+func OperationSchemaImports(s *Schema) (map[string]goImport, error) {
+	res := map[string]goImport{}
+
+	for _, p := range s.Properties {
+		imprts, err := GoSchemaImports(&openapi3.SchemaRef{Value: p.Schema.OAPISchema})
+		if err != nil {
+			return nil, err
+		}
+		MergeImports(res, imprts)
+	}
+
+	imprts, err := GoSchemaImports(&openapi3.SchemaRef{Value: s.OAPISchema})
+	if err != nil {
+		return nil, err
+	}
+	MergeImports(res, imprts)
+	return res, nil
+}
+
+func OperationImports(ops []OperationDefinition) (map[string]goImport, error) {
+	res := map[string]goImport{}
+	for _, op := range ops {
+		for _, pd := range [][]ParameterDefinition{op.PathParams, op.QueryParams} {
+			for _, p := range pd {
+				imprts, err := OperationSchemaImports(&p.Schema)
+				if err != nil {
+					return nil, err
+				}
+				MergeImports(res, imprts)
+			}
+		}
+
+		for _, b := range op.Bodies {
+			imprts, err := OperationSchemaImports(&b.Schema)
+			if err != nil {
+				return nil, err
+			}
+			MergeImports(res, imprts)
+		}
+
+		for _, b := range op.Responses {
+			for _, c := range b.Contents {
+				imprts, err := OperationSchemaImports(&c.Schema)
+				if err != nil {
+					return nil, err
+				}
+				MergeImports(res, imprts)
+			}
+		}
+
+	}
+	return res, nil
+}
+
 func GetTypeDefinitionsImports(swagger *openapi3.T, excludeSchemas []string) (map[string]goImport, error) {
 	res := map[string]goImport{}
 	schemaImports, err := GetSchemaImports(swagger.Components.Schemas, excludeSchemas)
@@ -811,9 +870,48 @@ func GetTypeDefinitionsImports(swagger *openapi3.T, excludeSchemas []string) (ma
 		return nil, err
 	}
 
-	for _, imprts := range []map[string]goImport{schemaImports, reqBodiesImports, responsesImports} {
-		for k, v := range imprts {
-			res[k] = v
+	parametersImports, err := GetParametersImports(swagger.Components.Parameters)
+	if err != nil {
+		return nil, err
+	}
+
+	for _, imprts := range []map[string]goImport{schemaImports, reqBodiesImports, responsesImports, parametersImports} {
+		MergeImports(res, imprts)
+	}
+	return res, nil
+}
+
+func GoSchemaImports(schemas ...*openapi3.SchemaRef) (map[string]goImport, error) {
+	res := map[string]goImport{}
+	for _, sref := range schemas {
+		if sref == nil || sref.Value == nil || IsGoTypeReference(sref.Ref) {
+			return nil, nil
+		}
+		if gi, err := ParseGoImportExtension(sref); err != nil {
+			return nil, err
+		} else {
+			if gi != nil {
+				res[gi.String()] = *gi
+			}
+		}
+		schemaVal := sref.Value
+
+		t := schemaVal.Type
+		switch t {
+		case "", "object":
+			for _, v := range schemaVal.Properties {
+				imprts, err := GoSchemaImports(v)
+				if err != nil {
+					return nil, err
+				}
+				MergeImports(res, imprts)
+			}
+		case "array":
+			imprts, err := GoSchemaImports(schemaVal.Items)
+			if err != nil {
+				return nil, err
+			}
+			MergeImports(res, imprts)
 		}
 	}
 	return res, nil
@@ -825,48 +923,31 @@ func GetSchemaImports(schemas map[string]*openapi3.SchemaRef, excludeSchemas []s
 	for _, schema := range excludeSchemas {
 		excludeSchemasMap[schema] = true
 	}
-	for _, schemaName := range SortedSchemaKeys(schemas) {
+	for schemaName, schema := range schemas {
 		if _, ok := excludeSchemasMap[schemaName]; ok {
 			continue
 		}
-		schema := schemas[schemaName].Value
-
-		if schema == nil || schema.Properties == nil {
-			continue
-		}
 
-		imprts, err := GetImports(schema.Properties)
+		imprts, err := GoSchemaImports(schema)
 		if err != nil {
 			return nil, err
 		}
-
-		for s, gi := range imprts {
-			res[s] = gi
-		}
+		MergeImports(res, imprts)
 	}
 	return res, nil
 }
 
 func GetRequestBodiesImports(bodies map[string]*openapi3.RequestBodyRef) (map[string]goImport, error) {
 	res := map[string]goImport{}
-	for _, requestBodyName := range SortedRequestBodyKeys(bodies) {
-		requestBodyRef := bodies[requestBodyName]
-		response := requestBodyRef.Value
+	for _, r := range bodies {
+		response := r.Value
 		jsonBody, found := response.Content["application/json"]
 		if found {
-			schema := jsonBody.Schema
-			if schema == nil || schema.Value == nil || schema.Value.Properties == nil {
-				continue
-			}
-
-			imprts, err := GetImports(schema.Value.Properties)
+			imprts, err := GoSchemaImports(jsonBody.Schema)
 			if err != nil {
 				return nil, err
 			}
-
-			for s, gi := range imprts {
-				res[s] = gi
-			}
+			MergeImports(res, imprts)
 		}
 	}
 	return res, nil
@@ -874,25 +955,31 @@ func GetRequestBodiesImports(bodies map[string]*openapi3.RequestBodyRef) (map[st
 
 func GetResponsesImports(responses map[string]*openapi3.ResponseRef) (map[string]goImport, error) {
 	res := map[string]goImport{}
-	for _, responseName := range SortedResponsesKeys(responses) {
-		responseOrRef := responses[responseName]
-		response := responseOrRef.Value
+	for _, r := range responses {
+		response := r.Value
 		jsonResponse, found := response.Content["application/json"]
 		if found {
-			schema := jsonResponse.Schema
-			if schema == nil || schema.Value == nil || schema.Value.Properties == nil {
-				continue
-			}
-
-			imprts, err := GetImports(schema.Value.Properties)
+			imprts, err := GoSchemaImports(jsonResponse.Schema)
 			if err != nil {
 				return nil, err
 			}
+			MergeImports(res, imprts)
+		}
+	}
+	return res, nil
+}
 
-			for s, gi := range imprts {
-				res[s] = gi
-			}
+func GetParametersImports(params map[string]*openapi3.ParameterRef) (map[string]goImport, error) {
+	res := map[string]goImport{}
+	for _, param := range params {
+		if param.Value == nil {
+			continue
+		}
+		imprts, err := GoSchemaImports(param.Value.Schema)
+		if err != nil {
+			return nil, err
 		}
+		MergeImports(res, imprts)
 	}
 	return res, nil
 }
diff --git a/pkg/codegen/extension.go b/pkg/codegen/extension.go
index a9ee43d..5d01c78 100644
--- a/pkg/codegen/extension.go
+++ b/pkg/codegen/extension.go
@@ -6,6 +6,7 @@ import (
 )
 
 const (
+	extPropGoImport     = "x-go-type-import"
 	extPropGoType       = "x-go-type"
 	extGoName           = "x-go-name"
 	extPropGoJsonIgnore = "x-go-json-ignore"
diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go
index 9d83bd5..607e5d0 100644
--- a/pkg/codegen/schema.go
+++ b/pkg/codegen/schema.go
@@ -27,7 +27,7 @@ type Schema struct {
 
 	Description string // The description of the element
 
-	UnionElements []string       // Possible elements of oneOf/anyOf union
+	UnionElements []UnionElement // Possible elements of oneOf/anyOf union
 	Discriminator *Discriminator // Describes which value is stored in a union
 
 	// If this is set, the schema will declare a type via alias, eg,
@@ -195,6 +195,23 @@ func (d *Discriminator) PropertyName() string {
 	return SchemaNameToTypeName(d.Property)
 }
 
+// UnionElement describe union element, based on prefix externalRef\d+ and real ref name from external schema.
+type UnionElement string
+
+// String returns externalRef\d+ and real ref name from external schema, like externalRef0.SomeType.
+func (u UnionElement) String() string {
+	return string(u)
+}
+
+// Method generate union method name for template functions `As/From/Merge`.
+func (u UnionElement) Method() string {
+	var method string
+	for _, part := range strings.Split(string(u), `.`) {
+		method += UppercaseFirstCharacter(part)
+	}
+	return method
+}
+
 func PropertiesEqual(a, b Property) bool {
 	return a.JsonFieldName == b.JsonFieldName && a.Schema.TypeDecl() == b.Schema.TypeDecl() && a.Required == b.Required
 }
@@ -728,7 +745,7 @@ func generateUnion(outSchema *Schema, elements openapi3.SchemaRefs, discriminato
 				}
 			}
 		}
-		outSchema.UnionElements = append(outSchema.UnionElements, elementSchema.GoType)
+		outSchema.UnionElements = append(outSchema.UnionElements, UnionElement(elementSchema.GoType))
 	}
 
 	return nil
diff --git a/pkg/codegen/template_helpers.go b/pkg/codegen/template_helpers.go
index a677404..3a7a15f 100644
--- a/pkg/codegen/template_helpers.go
+++ b/pkg/codegen/template_helpers.go
@@ -29,9 +29,9 @@ const (
 )
 
 var (
-	contentTypesJSON = []string{echo.MIMEApplicationJSON, "text/x-json"}
+	contentTypesJSON = []string{echo.MIMEApplicationJSON, "text/x-json", "application/problem+json"}
 	contentTypesYAML = []string{"application/yaml", "application/x-yaml", "text/yaml", "text/x-yaml"}
-	contentTypesXML  = []string{echo.MIMEApplicationXML, echo.MIMETextXML}
+	contentTypesXML  = []string{echo.MIMEApplicationXML, echo.MIMETextXML, "application/problems+xml"}
 
 	responseTypeSuffix = "Response"
 )
diff --git a/pkg/codegen/templates/imports.tmpl b/pkg/codegen/templates/imports.tmpl
index 376e1f9..ef43ef3 100644
--- a/pkg/codegen/templates/imports.tmpl
+++ b/pkg/codegen/templates/imports.tmpl
@@ -27,6 +27,7 @@ import (
 	"github.com/go-chi/chi/v5"
 	"github.com/labstack/echo/v4"
 	"github.com/gin-gonic/gin"
+	"github.com/gorilla/mux"
 	{{- range .ExternalImports}}
 	{{ . }}
 	{{- end}}
diff --git a/pkg/codegen/templates/union.tmpl b/pkg/codegen/templates/union.tmpl
index d233e13..eb015be 100644
--- a/pkg/codegen/templates/union.tmpl
+++ b/pkg/codegen/templates/union.tmpl
@@ -4,15 +4,15 @@
     {{$properties := .Schema.Properties -}}
     {{range .Schema.UnionElements}}
         {{$element := . -}}
-        // As{{.}} returns the union data inside the {{$typeName}} as a {{.}}
-        func (t {{$typeName}}) As{{.}}() ({{.}}, error) {
+        // As{{ .Method }} returns the union data inside the {{$typeName}} as a {{.}}
+        func (t {{$typeName}}) As{{ .Method }}() ({{.}}, error) {
             var body {{.}}
             err := json.Unmarshal(t.union, &body)
             return body, err
         }
 
-        // From{{.}} overwrites any union data inside the {{$typeName}} as the provided {{.}}
-        func (t *{{$typeName}}) From{{.}} (v {{.}}) error {
+        // From{{ .Method }} overwrites any union data inside the {{$typeName}} as the provided {{.}}
+        func (t *{{$typeName}}) From{{ .Method }} (v {{.}}) error {
             {{if $discriminator -}}
                 {{range $value, $type := $discriminator.Mapping -}}
                     {{if eq $type $element -}}
@@ -32,8 +32,8 @@
             return err
         }
 
-        // Merge{{.}} performs a merge with any union data inside the {{$typeName}}, using the provided {{.}}
-        func (t *{{$typeName}}) Merge{{.}} (v {{.}}) error {
+        // Merge{{ .Method }} performs a merge with any union data inside the {{$typeName}}, using the provided {{.}}
+        func (t *{{$typeName}}) Merge{{ .Method }} (v {{.}}) error {
             {{if $discriminator -}}
                 {{range $value, $type := $discriminator.Mapping -}}
                     {{if eq $type $element -}}
diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go
index 0796b33..a31b553 100644
--- a/pkg/codegen/utils.go
+++ b/pkg/codegen/utils.go
@@ -791,27 +791,26 @@ func findSchemaNameByRefPath(refPath string, spec *openapi3.T) (string, error) {
 	return "", nil
 }
 
-func GetImports(dict map[string]*openapi3.SchemaRef) (map[string]goImport, error) {
-	res := map[string]goImport{}
-	for _, v := range dict {
-		if v == nil || v.Value == nil {
-			continue
-		}
+func ParseGoImportExtension(v *openapi3.SchemaRef) (*goImport, error) {
+	if v.Value.Extensions[extPropGoImport] == nil || v.Value.Extensions[extPropGoType] == nil {
+		return nil, nil
+	}
 
-		if v.Value.Extensions["x-go-type-import"] == nil || v.Value.Extensions["x-go-type"] == nil {
-			continue
-		}
-		goTypeImportExt := v.Value.Extensions["x-go-type-import"]
+	goTypeImportExt := v.Value.Extensions[extPropGoImport]
 
-		if raw, ok := goTypeImportExt.(json.RawMessage); ok {
-			gi := goImport{}
-			if err := json.Unmarshal(raw, &gi); err != nil {
-				return nil, err
-			}
-			res[gi.String()] = gi
-		} else {
-			continue
+	if raw, ok := goTypeImportExt.(json.RawMessage); ok {
+		gi := goImport{}
+		if err := json.Unmarshal(raw, &gi); err != nil {
+			return nil, err
 		}
+		return &gi, nil
+	}
+
+	return nil, nil
+}
+
+func MergeImports(dst, src map[string]goImport) {
+	for k, v := range src {
+		dst[k] = v
 	}
-	return res, nil
 }


Test patch:
diff --git a/pkg/codegen/codegen_test.go b/pkg/codegen/codegen_test.go
index 7b6ee26..9994e07 100644
--- a/pkg/codegen/codegen_test.go
+++ b/pkg/codegen/codegen_test.go
@@ -20,9 +20,15 @@ import (
 	examplePetstore "github.com/deepmap/oapi-codegen/examples/petstore-expanded/echo/api"
 )
 
+const (
+	remoteRefFile = `https://raw.githubusercontent.com/deepmap/oapi-codegen/master/examples/petstore-expanded` +
+		`/petstore-expanded.yaml`
+	remoteRefImport = `github.com/deepmap/oapi-codegen/examples/petstore-expanded`
+)
+
 func checkLint(t *testing.T, filename string, code []byte) {
 	linter := new(lint.Linter)
-	problems, err := linter.Lint("test.gen.go", code)
+	problems, err := linter.Lint(filename, code)
 	assert.NoError(t, err)
 	assert.Len(t, problems, 0)
 }
@@ -190,12 +196,14 @@ type GetTestByNameResponse struct {
 	checkLint(t, "test.gen.go", []byte(code))
 }
 
-func TestXGoTypeImport(t *testing.T) {
+func TestGoTypeImport(t *testing.T) {
 	packageName := "api"
 	opts := Configuration{
 		PackageName: packageName,
 		Generate: GenerateOptions{
-			Models: true,
+			EchoServer:   true,
+			Models:       true,
+			EmbeddedSpec: true,
 		},
 	}
 	spec := "test_specs/x-go-type-import-pet.yaml"
@@ -211,23 +219,85 @@ func TestXGoTypeImport(t *testing.T) {
 	_, err = format.Source([]byte(code))
 	assert.NoError(t, err)
 
+	imports := []string{
+		`github.com/CavernaTechnologies/pgext`, // schemas - direct object
+		`myuuid "github.com/google/uuid"`,      // schemas - object
+		`github.com/lib/pq`,                    // schemas - array
+		`github.com/spf13/viper`,               // responses - direct object
+		`golang.org/x/text`,                    // responses - complex object
+		`golang.org/x/email`,                   // requestBodies - in components
+		`github.com/fatih/color`,               // parameters - query
+		`github.com/go-openapi/swag`,           // parameters - path
+		`github.com/jackc/pgtype`,              // direct parameters - path
+		`github.com/mailru/easyjson`,           // direct parameters - query
+		`github.com/subosito/gotenv`,           // direct request body
+	}
+
+	// Check import
+	for _, imp := range imports {
+		assert.Contains(t, code, imp)
+	}
+
+	// Make sure the generated code is valid:
+	checkLint(t, "test.gen.go", []byte(code))
+
+}
+
+func TestRemoteExternalReference(t *testing.T) {
+	packageName := "api"
+	opts := Configuration{
+		PackageName: packageName,
+		Generate: GenerateOptions{
+			Models: true,
+		},
+		ImportMapping: map[string]string{
+			remoteRefFile: remoteRefImport,
+		},
+	}
+	spec := "test_specs/remote-external-reference.yaml"
+	swagger, err := util.LoadSwagger(spec)
+	require.NoError(t, err)
+
+	// Run our code generation:
+	code, err := Generate(swagger, opts)
+	assert.NoError(t, err)
+	assert.NotEmpty(t, code)
+
+	// Check that we have valid (formattable) code:
+	_, err = format.Source([]byte(code))
+	assert.NoError(t, err)
+
 	// Check that we have a package:
 	assert.Contains(t, code, "package api")
 
 	// Check import
-	assert.Contains(t, code, `myuuid "github.com/google/uuid"`)
+	assert.Contains(t, code, `externalRef0 "github.com/deepmap/oapi-codegen/examples/petstore-expanded"`)
 
-	// Check generated struct
-	assert.Contains(t, code, "type Pet struct {\n\tAge myuuid.UUID `json:\"age\"`\n}")
+	// Check generated oneOf structure:
+	assert.Contains(t, code, `
+// ExampleSchema_Item defines model for ExampleSchema.Item.
+type ExampleSchema_Item struct {
+	union json.RawMessage
+}
+`)
 
-	// Check import
-	assert.Contains(t, code, `github.com/CavernaTechnologies/pgext`)
+	// Check generated oneOf structure As method:
+	assert.Contains(t, code, `
+// AsExternalRef0NewPet returns the union data inside the ExampleSchema_Item as a externalRef0.NewPet
+func (t ExampleSchema_Item) AsExternalRef0NewPet() (externalRef0.NewPet, error) {
+`)
 
-	// Check generated struct
-	assert.Contains(t, code, "type Person struct {\n\tAge pgext.Puint `json:\"age\"`\n}")
+	// Check generated oneOf structure From method:
+	assert.Contains(t, code, `
+// FromExternalRef0NewPet overwrites any union data inside the ExampleSchema_Item as the provided externalRef0.NewPet
+func (t *ExampleSchema_Item) FromExternalRef0NewPet(v externalRef0.NewPet) error {
+`)
 
-	// Check generated struct
-	assert.Contains(t, code, "type Car struct {\n\tAge int `json:\"age\"`\n}")
+	// Check generated oneOf structure Merge method:
+	assert.Contains(t, code, `
+// FromExternalRef0NewPet overwrites any union data inside the ExampleSchema_Item as the provided externalRef0.NewPet
+func (t *ExampleSchema_Item) FromExternalRef0NewPet(v externalRef0.NewPet) error {
+`)
 
 	// Make sure the generated code is valid:
 	checkLint(t, "test.gen.go", []byte(code))
diff --git a/pkg/codegen/test_specs/remote-external-reference.yaml b/pkg/codegen/test_specs/remote-external-reference.yaml
new file mode 100644
index 0000000..b966df1
--- /dev/null
+++ b/pkg/codegen/test_specs/remote-external-reference.yaml
@@ -0,0 +1,26 @@
+openapi: "3.0.0"
+info:
+  version: 1.0.0
+  title: Example with oneOf and external remote ref
+paths:
+  /check:
+    get:
+      summary: Return broken example
+      responses:
+        '200':
+          description: Ok
+          content:
+            application/json:
+              schema:
+                items:
+                  $ref: '#/components/schemas/exampleSchema'
+components:
+  schemas:
+    exampleSchema:
+      properties:
+        item:
+          type: object
+          oneOf:
+            - $ref: 'https://raw.githubusercontent.com/deepmap/oapi-codegen/master/examples/petstore-expanded/petstore-expanded.yaml#/components/schemas/NewPet'
+      required:
+        - item
diff --git a/pkg/codegen/test_specs/x-go-type-import-pet.yaml b/pkg/codegen/test_specs/x-go-type-import-pet.yaml
index 9df66b5..b236564 100644
--- a/pkg/codegen/test_specs/x-go-type-import-pet.yaml
+++ b/pkg/codegen/test_specs/x-go-type-import-pet.yaml
@@ -14,70 +14,111 @@ info:
 servers:
   - url: http://petstore.swagger.io/api
 paths:
-  /pets/{id}:
+  /schemas/pet-object:
     get:
-      summary: Returns a pet by ID
-      description: Returns a pet based on a single ID
-      operationId: findPetByID
-      parameters:
-        - name: id
-          in: path
-          description: ID of pet to fetch
-          required: true
-          schema:
-            type: integer
-            format: int64
+      description: return pet object
       responses:
         "200":
-          description: pet response
+          description: person response
           content:
             application/json:
               schema:
-                $ref: "#/components/schemas/Pet"
-  /person/{id}:
+                $ref: "#/components/schemas/PetObject"
+  /schemas/age-simple:
     get:
-      summary: Returns a person by ID
-      description: Returns a person based on a single ID
-      operationId: findPersonByID
-      parameters:
-        - name: id
-          in: path
-          description: ID of person to fetch
-          required: true
-          schema:
-            type: integer
-            format: int64
+      description: return pet object
       responses:
         "200":
           description: person response
           content:
             application/json:
               schema:
-                $ref: "#/components/schemas/Person"
-  /car/{id}:
+                $ref: "#/components/schemas/AgeSimple"
+
+  /schemas/schema-with-array:
     get:
-      summary: Returns a car by ID
-      description: Returns a car based on a single ID
-      operationId: findCarByID
-      parameters:
-        - name: id
-          in: path
-          description: ID of car to fetch
-          required: true
-          schema:
-            type: integer
-            format: int64
+      description: return schema object with array
       responses:
         "200":
-          description: car response
+          description: person response
           content:
             application/json:
               schema:
-                $ref: "#/components/schemas/Car"
+                $ref: "#/components/schemas/PetArray"
+
+  /responses/type:
+    get:
+      responses:
+        '200':
+          $ref: '#/components/responses/StringResponse'
+
+  /responses/complex-response:
+    get:
+      responses:
+        '200':
+          $ref: '#/components/responses/ComplexResponse'
+
+  /requests/:
+    post:
+      requestBody:
+        $ref: "#/components/requestBodies/RegisterBody"
+      responses:
+        '200':
+          $ref: '#/components/responses/ComplexResponse'
+
+  /parameters/query:
+    post:
+      parameters:
+        - $ref: "#/components/parameters/Version"
+      requestBody:
+        $ref: "#/components/requestBodies/RegisterBody"
+      responses:
+        '200':
+          $ref: '#/components/responses/ComplexResponse'
+
+  /parameters/{versionPath}:
+    post:
+      parameters:
+        - $ref: "#/components/parameters/VersionPath"
+      requestBody:
+        $ref: "#/components/requestBodies/RegisterBody"
+      responses:
+        '200':
+          $ref: '#/components/responses/ComplexResponse'
+
+  /requests/{path}:
+    post:
+      parameters:
+        - name: version
+          in: query
+          schema:
+            x-go-type: easyjson.Json
+            x-go-type-import:
+              path: github.com/mailru/easyjson
+        - name: path
+          in: path
+          schema:
+            x-go-type: pgtype.Color
+            x-go-type-import:
+              path: github.com/jackc/pgtype
+      requestBody:
+        required: true
+        content:
+          application/json:
+            schema:
+              type: object
+              properties:
+                email:
+                  x-go-type: gotenv.Env
+                  x-go-type-import:
+                    path: github.com/subosito/gotenv
+      responses:
+        '200':
+            $ref: '#/components/responses/ComplexResponse'
 
 components:
   schemas:
-    Pet:
+    PetObject:
       properties:
         age:
           x-go-type: myuuid.UUID
@@ -86,17 +127,67 @@ components:
             name: myuuid
       required:
         - age
-    Person:
-      properties:
-        age:
-          x-go-type: pgext.Puint
-          x-go-type-import:
-            path: github.com/CavernaTechnologies/pgext
-      required:
-        - age
-    Car:
-      properties:
-        age:
-          type: integer
-      required:
-        - age
+    AgeSimple:
+      x-go-type: pgext.Puint
+      x-go-type-import:
+        path: github.com/CavernaTechnologies/pgext
+    PetArray:
+      type: array
+      items:
+        x-go-type: pq.Int
+        x-go-type-import:
+          path: github.com/lib/pq
+
+  responses:
+    StringResponse:
+      description: An image.
+      content:
+        application/json:
+          schema:
+            type: string
+            x-go-type: viper.ID
+            x-go-type-import:
+              path: github.com/spf13/viper
+    ComplexResponse:
+      description: Complex response
+      content:
+        application/json:
+          schema:
+            type: object
+            properties:
+              keys:
+                type: array
+                items:
+                  x-go-type: text.Text
+                  x-go-type-import:
+                    path: golang.org/x/text
+
+  requestBodies:
+    RegisterBody:
+      required: true
+      content:
+        application/json:
+          schema:
+            type: object
+            properties:
+              email:
+                x-go-type: email.Email
+                x-go-type-import:
+                  path: golang.org/x/email
+
+  parameters:
+    Version:
+      name: version
+      in: query
+      schema:
+        x-go-type: color.Color
+        x-go-type-import:
+          path: github.com/fatih/color
+
+    VersionPath:
+      name: versionPath
+      in: path
+      schema:
+        x-go-type: swag.Swag
+        x-go-type-import:
+          path: github.com/go-openapi/swag
\ No newline at end of file
diff --git a/pkg/codegen/utils_test.go b/pkg/codegen/utils_test.go
index 7bbfaff..518e287 100644
--- a/pkg/codegen/utils_test.go
+++ b/pkg/codegen/utils_test.go
@@ -14,8 +14,6 @@
 package codegen
 
 import (
-	"encoding/json"
-	"fmt"
 	"testing"
 
 	"github.com/getkin/kin-openapi/openapi3"
@@ -434,44 +432,3 @@ func TestSchemaNameToTypeName(t *testing.T) {
 		assert.Equal(t, want, SchemaNameToTypeName(in))
 	}
 }
-
-func TestGetImports(t *testing.T) {
-	schemas := map[string]*openapi3.SchemaRef{
-		"age": {
-			Value: &openapi3.Schema{
-				ExtensionProps: openapi3.ExtensionProps{
-					Extensions: map[string]interface{}{
-						"x-go-type-import": json.RawMessage(
-							`{"name": "hello", "path": "github.com/google/uuid"}`,
-						),
-						"x-go-type": json.RawMessage(
-							"hello.UUID",
-						),
-					},
-				},
-			},
-		},
-		"name": {
-			Value: &openapi3.Schema{
-				ExtensionProps: openapi3.ExtensionProps{
-					Extensions: map[string]interface{}{"other-tag": json.RawMessage(
-						`bla`,
-					)},
-				},
-			},
-		},
-		"value": nil,
-	}
-
-	expected := map[string]goImport{
-		fmt.Sprintf("%s %q", "hello", "github.com/google/uuid"): {
-			Name: "hello",
-			Path: "github.com/google/uuid",
-		},
-	}
-
-	res, err := GetImports(schemas)
-
-	assert.NoError(t, err)
-	assert.Equal(t, expected, res)
-}