From 12c47e18918a54222236b648709097936b84466c Mon Sep 17 00:00:00 2001 From: Vladimir Stepanov Date: Sat, 18 Jun 2022 14:21:05 +0600 Subject: [PATCH 01/15] implement new field: x-go-type-import --- pkg/codegen/codegen.go | 44 +++++++++++++++++++++++++++++++++++++++ pkg/codegen/utils.go | 26 +++++++++++++++++++++++ pkg/codegen/utils_test.go | 37 ++++++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+) diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index 1f827fb9f..567cd5900 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -150,6 +150,14 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) { return "", fmt.Errorf("error generating constants: %w", err) } + typeDefinitionsImports, err := GetTypeDefinitionsImports(spec, opts.OutputOptions.ExcludeSchemas) + if err != nil { + return "", fmt.Errorf("error getting type definition imports") + } + + for k, v := range typeDefinitionsImports { + importMapping[k] = v + } } var echoServerOut string @@ -763,3 +771,39 @@ func LoadTemplates(src embed.FS, t *template.Template) error { return nil }) } + +func GetTypeDefinitionsImports(swagger *openapi3.T, excludeSchemas []string) (map[string]goImport, error) { + schemaImports, err := GetSchemaImports(swagger.Components.Schemas, excludeSchemas) + if err != nil { + return nil, err + } + return schemaImports, nil +} + +func GetSchemaImports(schemas map[string]*openapi3.SchemaRef, excludeSchemas []string) (map[string]goImport, error) { + res := map[string]goImport{} + excludeSchemasMap := make(map[string]bool) + for _, schema := range excludeSchemas { + excludeSchemasMap[schema] = true + } + for _, schemaName := range SortedSchemaKeys(schemas) { + if _, ok := excludeSchemasMap[schemaName]; ok { + continue + } + schema := schemas[schemaName].Value + + if schema.Properties == nil { + continue + } + + schemaImports, err := GetImportsFromSchema(schema.Properties) + if err != nil { + return nil, err + } + + for k, v := range schemaImports { + res[k] = v + } + } + return res, nil +} diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go index c713002b4..27745f731 100644 --- a/pkg/codegen/utils.go +++ b/pkg/codegen/utils.go @@ -14,6 +14,7 @@ package codegen import ( + "encoding/json" "fmt" "net/url" "regexp" @@ -790,3 +791,28 @@ func findSchemaNameByRefPath(refPath string, spec *openapi3.T) (string, error) { } return "", nil } + +func GetImportsFromSchema(dict map[string]*openapi3.SchemaRef) (map[string]goImport, error) { + res := map[string]goImport{} + for _, v := range dict { + if v == nil { + continue + } + goTypeImportExt := v.Value.Extensions["x-go-type-import"] + if goTypeImportExt == nil { + continue + } + + if raw, ok := goTypeImportExt.(json.RawMessage); ok { + gi := goImport{} + if err := json.Unmarshal(raw, &gi); err != nil { + return nil, err + } + res[gi.Name+":"+gi.Path] = gi + } else { + continue + } + } + + return res, nil +} diff --git a/pkg/codegen/utils_test.go b/pkg/codegen/utils_test.go index 0b13ee8b1..92ff0f287 100644 --- a/pkg/codegen/utils_test.go +++ b/pkg/codegen/utils_test.go @@ -14,6 +14,7 @@ package codegen import ( + "encoding/json" "testing" "github.com/getkin/kin-openapi/openapi3" @@ -376,3 +377,39 @@ func TestSchemaNameToTypeName(t *testing.T) { assert.Equal(t, want, SchemaNameToTypeName(in)) } } + +func TestGetImportsFromSchemaKeys(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"}`, + )}, + }, + }, + }, + "name": { + Value: &openapi3.Schema{ + ExtensionProps: openapi3.ExtensionProps{ + Extensions: map[string]interface{}{"other-tag": json.RawMessage( + `bla`, + )}, + }, + }, + }, + "value": nil, + } + + expected := map[string]goImport{ + "hello:github.com/google/uuid": { + Name: "hello", + Path: "github.com/google/uuid", + }, + } + + res, err := GetImportsFromSchema(schemas) + + assert.NoError(t, err) + assert.Equal(t, expected, res) +} From dccfb662d9d92e25004250378fcec7f3a1cce684 Mon Sep 17 00:00:00 2001 From: Vladimir Stepanov Date: Sat, 18 Jun 2022 15:01:13 +0600 Subject: [PATCH 02/15] implement getting of request bodies imports --- pkg/codegen/codegen.go | 41 +++++++++++++++++++++++++++++++++++++++-- pkg/codegen/utils.go | 1 - 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index 567cd5900..7f45eb272 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -773,11 +773,23 @@ func LoadTemplates(src embed.FS, t *template.Template) error { } func GetTypeDefinitionsImports(swagger *openapi3.T, excludeSchemas []string) (map[string]goImport, error) { + res := map[string]goImport{} schemaImports, err := GetSchemaImports(swagger.Components.Schemas, excludeSchemas) if err != nil { return nil, err } - return schemaImports, nil + + reqBodiesImports, err := GetRequestBodiesImports(swagger.Components.RequestBodies) + if err != nil { + return nil, err + } + + for _, imprts := range []map[string]goImport{schemaImports, reqBodiesImports} { + for k, v := range imprts { + res[k] = v + } + } + return res, nil } func GetSchemaImports(schemas map[string]*openapi3.SchemaRef, excludeSchemas []string) (map[string]goImport, error) { @@ -792,7 +804,7 @@ func GetSchemaImports(schemas map[string]*openapi3.SchemaRef, excludeSchemas []s } schema := schemas[schemaName].Value - if schema.Properties == nil { + if schema == nil || schema.Properties == nil { continue } @@ -807,3 +819,28 @@ func GetSchemaImports(schemas map[string]*openapi3.SchemaRef, excludeSchemas []s } 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 + jsonBody, found := response.Content["application/json"] + if found { + schema := jsonBody.Schema + if schema == nil || schema.Value == nil || schema.Value.Properties == nil { + continue + } + + schemaImports, err := GetImportsFromSchema(schema.Value.Properties) + if err != nil { + return nil, err + } + + for k, v := range schemaImports { + res[k] = v + } + } + } + return res, nil +} diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go index 27745f731..f7794a9a6 100644 --- a/pkg/codegen/utils.go +++ b/pkg/codegen/utils.go @@ -813,6 +813,5 @@ func GetImportsFromSchema(dict map[string]*openapi3.SchemaRef) (map[string]goImp continue } } - return res, nil } From 2970a7c79f69094c9eb40232290355e7eec2f5fe Mon Sep 17 00:00:00 2001 From: Vladimir Stepanov Date: Sat, 18 Jun 2022 15:23:20 +0600 Subject: [PATCH 03/15] implement getting of responses imports --- pkg/codegen/codegen.go | 41 +++++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index 7f45eb272..f26c8c5f5 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -784,7 +784,12 @@ func GetTypeDefinitionsImports(swagger *openapi3.T, excludeSchemas []string) (ma return nil, err } - for _, imprts := range []map[string]goImport{schemaImports, reqBodiesImports} { + responsesImports, err := GetResponsesImports(swagger.Components.Responses) + if err != nil { + return nil, err + } + + for _, imprts := range []map[string]goImport{schemaImports, reqBodiesImports, responsesImports} { for k, v := range imprts { res[k] = v } @@ -793,6 +798,7 @@ func GetTypeDefinitionsImports(swagger *openapi3.T, excludeSchemas []string) (ma } func GetSchemaImports(schemas map[string]*openapi3.SchemaRef, excludeSchemas []string) (map[string]goImport, error) { + var err error res := map[string]goImport{} excludeSchemasMap := make(map[string]bool) for _, schema := range excludeSchemas { @@ -808,20 +814,17 @@ func GetSchemaImports(schemas map[string]*openapi3.SchemaRef, excludeSchemas []s continue } - schemaImports, err := GetImportsFromSchema(schema.Properties) + res, err = GetImportsFromSchema(schema.Properties) if err != nil { return nil, err } - - for k, v := range schemaImports { - res[k] = v - } } return res, nil } func GetRequestBodiesImports(bodies map[string]*openapi3.RequestBodyRef) (map[string]goImport, error) { - res := map[string]goImport{} + var res map[string]goImport + var err error for _, requestBodyName := range SortedRequestBodyKeys(bodies) { requestBodyRef := bodies[requestBodyName] response := requestBodyRef.Value @@ -832,13 +835,31 @@ func GetRequestBodiesImports(bodies map[string]*openapi3.RequestBodyRef) (map[st continue } - schemaImports, err := GetImportsFromSchema(schema.Value.Properties) + res, err = GetImportsFromSchema(schema.Value.Properties) if err != nil { return nil, err } + } + } + return res, nil +} - for k, v := range schemaImports { - res[k] = v +func GetResponsesImports(responses map[string]*openapi3.ResponseRef) (map[string]goImport, error) { + var res map[string]goImport + var err error + for _, responseName := range SortedResponsesKeys(responses) { + responseOrRef := responses[responseName] + response := responseOrRef.Value + jsonResponse, found := response.Content["application/json"] + if found { + schema := jsonResponse.Schema + if schema == nil || schema.Value == nil || schema.Value.Properties == nil { + continue + } + + res, err = GetImportsFromSchema(schema.Value.Properties) + if err != nil { + return nil, err } } } From b4704515205974ae9353810d8b04d729b5f38b09 Mon Sep 17 00:00:00 2001 From: Vladimir Stepanov Date: Sat, 18 Jun 2022 15:26:23 +0600 Subject: [PATCH 04/15] refactoring: rename GetImportsFromSchema to GetImports --- pkg/codegen/codegen.go | 6 +++--- pkg/codegen/utils.go | 2 +- pkg/codegen/utils_test.go | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index f26c8c5f5..4604aa70f 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -814,7 +814,7 @@ func GetSchemaImports(schemas map[string]*openapi3.SchemaRef, excludeSchemas []s continue } - res, err = GetImportsFromSchema(schema.Properties) + res, err = GetImports(schema.Properties) if err != nil { return nil, err } @@ -835,7 +835,7 @@ func GetRequestBodiesImports(bodies map[string]*openapi3.RequestBodyRef) (map[st continue } - res, err = GetImportsFromSchema(schema.Value.Properties) + res, err = GetImports(schema.Value.Properties) if err != nil { return nil, err } @@ -857,7 +857,7 @@ func GetResponsesImports(responses map[string]*openapi3.ResponseRef) (map[string continue } - res, err = GetImportsFromSchema(schema.Value.Properties) + res, err = GetImports(schema.Value.Properties) if err != nil { return nil, err } diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go index f7794a9a6..59fd37b89 100644 --- a/pkg/codegen/utils.go +++ b/pkg/codegen/utils.go @@ -792,7 +792,7 @@ func findSchemaNameByRefPath(refPath string, spec *openapi3.T) (string, error) { return "", nil } -func GetImportsFromSchema(dict map[string]*openapi3.SchemaRef) (map[string]goImport, error) { +func GetImports(dict map[string]*openapi3.SchemaRef) (map[string]goImport, error) { res := map[string]goImport{} for _, v := range dict { if v == nil { diff --git a/pkg/codegen/utils_test.go b/pkg/codegen/utils_test.go index 92ff0f287..435766ffc 100644 --- a/pkg/codegen/utils_test.go +++ b/pkg/codegen/utils_test.go @@ -378,7 +378,7 @@ func TestSchemaNameToTypeName(t *testing.T) { } } -func TestGetImportsFromSchemaKeys(t *testing.T) { +func TestGetImports(t *testing.T) { schemas := map[string]*openapi3.SchemaRef{ "age": { Value: &openapi3.Schema{ @@ -408,7 +408,7 @@ func TestGetImportsFromSchemaKeys(t *testing.T) { }, } - res, err := GetImportsFromSchema(schemas) + res, err := GetImports(schemas) assert.NoError(t, err) assert.Equal(t, expected, res) From 4f29fe572bf1ad012f42c93ef37607eaf7873eb8 Mon Sep 17 00:00:00 2001 From: Vladimir Stepanov Date: Sat, 18 Jun 2022 15:34:36 +0600 Subject: [PATCH 05/15] refactoring: add error wrapping --- pkg/codegen/codegen.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index 4604aa70f..dec68b7c3 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -152,7 +152,7 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) { typeDefinitionsImports, err := GetTypeDefinitionsImports(spec, opts.OutputOptions.ExcludeSchemas) if err != nil { - return "", fmt.Errorf("error getting type definition imports") + return "", fmt.Errorf("error getting type definition imports: %w", err) } for k, v := range typeDefinitionsImports { From 8ffb91bd9f4404c2eaa1885f7fd9475b039ff9b9 Mon Sep 17 00:00:00 2001 From: Vladimir Stepanov Date: Sat, 18 Jun 2022 15:43:52 +0600 Subject: [PATCH 06/15] update README --- README.md | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5cc41ccd4..47bf4ee1c 100644 --- a/README.md +++ b/README.md @@ -533,7 +533,32 @@ which help you to use the various OpenAPI 3 Authentication mechanism. ``` Name string `json:"name" tag1:"value1" tag2:"value2"` ``` - +- `x-go-type-import`: adds extra Go imports to your generated code. It can help you, when you want to + choose your own import package for `x-go-type`. + + ```yaml + schemas: + Pet: + properties: + age: + x-go-type: uuid.UUID + x-go-type-import: + name: uuid + path: github.com/google/uuid + ``` + After code generation you will get this: + ```go + import ( + ... + uuid "github.com/google/uuid" + ) + + //Pet defines model for Pet. + type Pet struct { + Age *hello.UUID `json:"age,omitempty"` + } + + ``` ## Using `oapi-codegen` From 325e13f1a1adc5b8556dad1a7d18714ce4650a4c Mon Sep 17 00:00:00 2001 From: Vladimir Stepanov Date: Mon, 20 Jun 2022 09:23:30 +0600 Subject: [PATCH 07/15] fix: generate import only if define x-go-type and x-go-type-import --- pkg/codegen/utils.go | 9 +++++---- pkg/codegen/utils_test.go | 14 ++++++++++---- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go index 59fd37b89..1f244f3fb 100644 --- a/pkg/codegen/utils.go +++ b/pkg/codegen/utils.go @@ -795,20 +795,21 @@ func findSchemaNameByRefPath(refPath string, spec *openapi3.T) (string, error) { func GetImports(dict map[string]*openapi3.SchemaRef) (map[string]goImport, error) { res := map[string]goImport{} for _, v := range dict { - if v == nil { + if v == nil || v.Value == nil { continue } - goTypeImportExt := v.Value.Extensions["x-go-type-import"] - if goTypeImportExt == 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"] if raw, ok := goTypeImportExt.(json.RawMessage); ok { gi := goImport{} if err := json.Unmarshal(raw, &gi); err != nil { return nil, err } - res[gi.Name+":"+gi.Path] = gi + res[gi.String()] = gi } else { continue } diff --git a/pkg/codegen/utils_test.go b/pkg/codegen/utils_test.go index 435766ffc..64c8b9133 100644 --- a/pkg/codegen/utils_test.go +++ b/pkg/codegen/utils_test.go @@ -15,6 +15,7 @@ package codegen import ( "encoding/json" + "fmt" "testing" "github.com/getkin/kin-openapi/openapi3" @@ -383,9 +384,14 @@ func TestGetImports(t *testing.T) { "age": { Value: &openapi3.Schema{ ExtensionProps: openapi3.ExtensionProps{ - Extensions: map[string]interface{}{"x-go-type-import": json.RawMessage( - `{"name": "hello", "path": "github.com/google/uuid"}`, - )}, + Extensions: map[string]interface{}{ + "x-go-type-import": json.RawMessage( + `{"name": "hello", "path": "github.com/google/uuid"}`, + ), + "x-go-type": json.RawMessage( + "hello.UUID", + ), + }, }, }, }, @@ -402,7 +408,7 @@ func TestGetImports(t *testing.T) { } expected := map[string]goImport{ - "hello:github.com/google/uuid": { + fmt.Sprintf("%s %q", "hello", "github.com/google/uuid"): { Name: "hello", Path: "github.com/google/uuid", }, From 3eb97bf67853075b00e6e584a7fbcc77140650d4 Mon Sep 17 00:00:00 2001 From: Vladimir Stepanov Date: Mon, 20 Jun 2022 09:27:57 +0600 Subject: [PATCH 08/15] fix: bug of import generation --- pkg/codegen/codegen.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index dec68b7c3..71d209e6c 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -139,6 +139,7 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) { } 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 { @@ -150,14 +151,10 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) { return "", fmt.Errorf("error generating constants: %w", err) } - typeDefinitionsImports, err := GetTypeDefinitionsImports(spec, opts.OutputOptions.ExcludeSchemas) + xGoTypeImports, err = GetTypeDefinitionsImports(spec, opts.OutputOptions.ExcludeSchemas) if err != nil { return "", fmt.Errorf("error getting type definition imports: %w", err) } - - for k, v := range typeDefinitionsImports { - importMapping[k] = v - } } var echoServerOut string @@ -220,6 +217,11 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) { w := bufio.NewWriter(&buf) externalImports := importMapping.GoImports() + if xGoTypeImports != nil { + for _, v := range xGoTypeImports { + externalImports = append(externalImports, v.String()) + } + } importsOut, err := GenerateImports(t, externalImports, opts.PackageName) if err != nil { return "", fmt.Errorf("error generating imports: %w", err) From 5bf687fe12943540f3ec114182e8eacc9ebf4cb9 Mon Sep 17 00:00:00 2001 From: Vladimir Stepanov Date: Mon, 20 Jun 2022 09:44:05 +0600 Subject: [PATCH 09/15] fix: remove useless checking --- pkg/codegen/codegen.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index 71d209e6c..92e915ff3 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -217,10 +217,8 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) { w := bufio.NewWriter(&buf) externalImports := importMapping.GoImports() - if xGoTypeImports != nil { - for _, v := range xGoTypeImports { - externalImports = append(externalImports, v.String()) - } + for _, v := range xGoTypeImports { + externalImports = append(externalImports, v.String()) } importsOut, err := GenerateImports(t, externalImports, opts.PackageName) if err != nil { From 0d80d72574920e163e4aa8ac19106887849227b8 Mon Sep 17 00:00:00 2001 From: Vladimir Stepanov Date: Tue, 21 Jun 2022 00:33:36 +0600 Subject: [PATCH 10/15] docs: add description for 'name' field --- README.md | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 47bf4ee1c..840db4b12 100644 --- a/README.md +++ b/README.md @@ -536,29 +536,56 @@ which help you to use the various OpenAPI 3 Authentication mechanism. - `x-go-type-import`: adds extra Go imports to your generated code. It can help you, when you want to choose your own import package for `x-go-type`. - ```yaml + ```yaml schemas: Pet: properties: age: x-go-type: uuid.UUID x-go-type-import: - name: uuid + name: myuuid path: github.com/google/uuid - ``` + ``` After code generation you will get this: ```go import ( ... - uuid "github.com/google/uuid" + myuuid "github.com/google/uuid" ) //Pet defines model for Pet. type Pet struct { - Age *hello.UUID `json:"age,omitempty"` + Age *myuuid.UUID `json:"age,omitempty"` } ``` + `name` is an optional parameter. Example without name: + + ```yaml + components: + schemas: + Pet: + properties: + age: + x-go-type: uuid.UUID + x-go-type-import: + path: github.com/google/uuid + required: + - age + ``` + + After code generation you will get this result: + + ```go + import ( + "github.com/google/uuid" + ) + + // Pet defines model for Pet. + type Pet struct { + Age uuid.UUID `json:"age"` + } + ``` ## Using `oapi-codegen` From 53dbe95819073cdbdc5e50b06e4233485d4e3ad2 Mon Sep 17 00:00:00 2001 From: Vladimir Stepanov Date: Thu, 23 Jun 2022 14:51:57 +0600 Subject: [PATCH 11/15] test: add tests for x-go-type-import into codegen_test --- pkg/codegen/codegen_test.go | 54 ++++++++++++++++--- .../test_specs/x-go-type-import-pet.yaml | 47 ++++++++++++++++ 2 files changed, 94 insertions(+), 7 deletions(-) create mode 100644 pkg/codegen/test_specs/x-go-type-import-pet.yaml diff --git a/pkg/codegen/codegen_test.go b/pkg/codegen/codegen_test.go index 8d333a6e4..d5840b354 100644 --- a/pkg/codegen/codegen_test.go +++ b/pkg/codegen/codegen_test.go @@ -8,6 +8,10 @@ import ( "net/http" "testing" + "github.com/stretchr/testify/require" + + "github.com/deepmap/oapi-codegen/pkg/util" + "github.com/getkin/kin-openapi/openapi3" "github.com/golangci/lint-1" "github.com/stretchr/testify/assert" @@ -16,6 +20,13 @@ import ( examplePetstore "github.com/deepmap/oapi-codegen/examples/petstore-expanded/echo/api" ) +func checkLint(t *testing.T, filename string, code []byte) { + linter := new(lint.Linter) + problems, err := linter.Lint("test.gen.go", code) + assert.NoError(t, err) + assert.Len(t, problems, 0) +} + func TestExamplePetStoreCodeGeneration(t *testing.T) { // Input vars for code generation: @@ -58,10 +69,7 @@ func TestExamplePetStoreCodeGeneration(t *testing.T) { `) // Make sure the generated code is valid: - linter := new(lint.Linter) - problems, err := linter.Lint("test.gen.go", []byte(code)) - assert.NoError(t, err) - assert.Len(t, problems, 0) + checkLint(t, "test.gen.go", []byte(code)) } func TestExamplePetStoreCodeGenerationWithUserTemplates(t *testing.T) { @@ -179,10 +187,42 @@ type GetTestByNameResponse struct { assert.Contains(t, code, "DeadSince *time.Time `json:\"dead_since,omitempty\" tag1:\"value1\" tag2:\"value2\"`") // Make sure the generated code is valid: - linter := new(lint.Linter) - problems, err := linter.Lint("test.gen.go", []byte(code)) + checkLint(t, "test.gen.go", []byte(code)) +} + +func TestXGoTypeImport(t *testing.T) { + packageName := "api" + opts := Configuration{ + PackageName: packageName, + Generate: GenerateOptions{ + Models: true, + }, + } + spec := "test_specs/x-go-type-import-pet.yaml" + swagger, err := util.LoadSwagger(spec) + require.NoError(t, err) + + // Run our code generation: + code, err := Generate(swagger, opts) assert.NoError(t, err) - assert.Len(t, problems, 0) + 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"`) + + // Check generated struct + assert.Contains(t, code, "type Pet struct {\n\tAge myuuid.UUID `json:\"age\"`\n}") + + // Make sure the generated code is valid: + checkLint(t, "test.gen.go", []byte(code)) + } //go:embed test_spec.yaml diff --git a/pkg/codegen/test_specs/x-go-type-import-pet.yaml b/pkg/codegen/test_specs/x-go-type-import-pet.yaml new file mode 100644 index 000000000..4fea6ff9e --- /dev/null +++ b/pkg/codegen/test_specs/x-go-type-import-pet.yaml @@ -0,0 +1,47 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: Swagger Petstore + description: A sample API that uses a petstore as an example to demonstrate features in the OpenAPI 3.0 specification + termsOfService: http://swagger.io/terms/ + contact: + name: Swagger API Team + email: apiteam@swagger.io + url: http://swagger.io + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html +servers: + - url: http://petstore.swagger.io/api +paths: + /pets/{id}: + 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 + responses: + '200': + description: pet response + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' +components: + schemas: + Pet: + properties: + age: + x-go-type: myuuid.UUID + x-go-type-import: + path: github.com/google/uuid + name: myuuid + required: + - age From 9ba3514478ac0cd6391c513e0677945c33c94fd9 Mon Sep 17 00:00:00 2001 From: Vladimir Stepanov Date: Thu, 23 Jun 2022 14:57:57 +0600 Subject: [PATCH 12/15] docs: fix README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 840db4b12..4c852aa91 100644 --- a/README.md +++ b/README.md @@ -541,7 +541,7 @@ which help you to use the various OpenAPI 3 Authentication mechanism. Pet: properties: age: - x-go-type: uuid.UUID + x-go-type: myuuid.UUID x-go-type-import: name: myuuid path: github.com/google/uuid @@ -559,7 +559,7 @@ which help you to use the various OpenAPI 3 Authentication mechanism. } ``` - `name` is an optional parameter. Example without name: + `name` is an optional parameter. Example: ```yaml components: From a643ce11a8dcf13f3dce5fae93bcbb653fe56fee Mon Sep 17 00:00:00 2001 From: Vladimir Stepanov Date: Thu, 23 Jun 2022 16:27:49 +0600 Subject: [PATCH 13/15] refactor: fix error msg --- pkg/codegen/codegen.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index 92e915ff3..9b1fee506 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -153,7 +153,7 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) { xGoTypeImports, err = GetTypeDefinitionsImports(spec, opts.OutputOptions.ExcludeSchemas) if err != nil { - return "", fmt.Errorf("error getting type definition imports: %w", err) + return "", fmt.Errorf("error while getting type definition imports: %w", err) } } From 7f2afdeb8cc1b9a55f73645bb76fd60f0bd5f5d2 Mon Sep 17 00:00:00 2001 From: Vladimir Stepanov Date: Thu, 23 Jun 2022 16:38:45 +0600 Subject: [PATCH 14/15] refactor: use existing importMap type --- pkg/codegen/codegen.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index 9b1fee506..49aebb115 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -216,10 +216,7 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) { var buf bytes.Buffer w := bufio.NewWriter(&buf) - externalImports := importMapping.GoImports() - for _, v := range xGoTypeImports { - externalImports = append(externalImports, v.String()) - } + externalImports := append(importMapping.GoImports(), importMap(xGoTypeImports).GoImports()...) importsOut, err := GenerateImports(t, externalImports, opts.PackageName) if err != nil { return "", fmt.Errorf("error generating imports: %w", err) From 420017b6bc836e026560eae349d3bac924845470 Mon Sep 17 00:00:00 2001 From: Vladimir Stepanov Date: Thu, 23 Jun 2022 16:40:42 +0600 Subject: [PATCH 15/15] refactor: fix error msg --- pkg/codegen/codegen.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go index 49aebb115..338833eb7 100644 --- a/pkg/codegen/codegen.go +++ b/pkg/codegen/codegen.go @@ -153,7 +153,7 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) { xGoTypeImports, err = GetTypeDefinitionsImports(spec, opts.OutputOptions.ExcludeSchemas) if err != nil { - return "", fmt.Errorf("error while getting type definition imports: %w", err) + return "", fmt.Errorf("error getting type definition imports: %w", err) } }