From 1dd95900640479026de568479a24b2f8f1f13adc Mon Sep 17 00:00:00 2001 From: Ian Cubbon Date: Mon, 16 Oct 2023 20:35:39 -0700 Subject: [PATCH] [Go-server] - Support for Enums in the Path and Query (#16781) * Add support for Enums to be part of the Path and Query Supports optional Query Enums and Lists of Enums as well Add an example endpoint that covers the added scenarios Added an import mapping for the GoServerCodegen for "fmt" when a model is an enum. Expanded the Enum Model for the Go Server to have validation. Copied this logic from the Go Client Enum Model. * Fix identation of examples * Pre-allocate the capacity of the slice of Enums to be the correct size. * Formatting and updated examples * Empty-Commit * Switch to using a map to store the valid enum values * Fixed pointer derefs missed from previous change in PR * More fixing of pointer to not pointer * Create a map for validation and a list of enums for messaging --- .../codegen/languages/GoServerCodegen.java | 1 + .../go-server/controller-api.mustache | 64 +++++++++++++++- .../main/resources/go-server/model.mustache | 39 +++++++++- .../resources/3_0/go-server/petstore.yaml | 60 +++++++++++++++ .../petstore/go/go-petstore/go/api_pet.go | 10 ++- .../go-api-server/.openapi-generator/FILES | 2 + .../petstore/go-api-server/api/openapi.yaml | 62 +++++++++++++++ .../server/petstore/go-api-server/go/api.go | 2 + .../petstore/go-api-server/go/api_pet.go | 56 +++++++++++++- .../go-api-server/go/api_pet_service.go | 14 ++++ .../petstore/go-api-server/go/model_gender.go | 66 ++++++++++++++++ .../go-api-server/go/model_species.go | 75 +++++++++++++++++++ .../go-chi-server/.openapi-generator/FILES | 2 + .../petstore/go-chi-server/api/openapi.yaml | 62 +++++++++++++++ .../server/petstore/go-chi-server/go/api.go | 2 + .../petstore/go-chi-server/go/api_pet.go | 55 +++++++++++++- .../go-chi-server/go/api_pet_service.go | 14 ++++ .../petstore/go-chi-server/go/model_gender.go | 66 ++++++++++++++++ .../go-chi-server/go/model_species.go | 75 +++++++++++++++++++ 19 files changed, 718 insertions(+), 9 deletions(-) create mode 100644 samples/server/petstore/go-api-server/go/model_gender.go create mode 100644 samples/server/petstore/go-api-server/go/model_species.go create mode 100644 samples/server/petstore/go-chi-server/go/model_gender.go create mode 100644 samples/server/petstore/go-chi-server/go/model_species.go diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/GoServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/GoServerCodegen.java index 97deeb58442..fff4b41bb7a 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/GoServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/GoServerCodegen.java @@ -301,6 +301,7 @@ public class GoServerCodegen extends AbstractGoCodegen { CodegenModel model = m.getModel(); if (model.isEnum) { + imports.add(createMapping("import", "fmt")); continue; } diff --git a/modules/openapi-generator/src/main/resources/go-server/controller-api.mustache b/modules/openapi-generator/src/main/resources/go-server/controller-api.mustache index 55ca127692b..5769d40a18c 100644 --- a/modules/openapi-generator/src/main/resources/go-server/controller-api.mustache +++ b/modules/openapi-generator/src/main/resources/go-server/controller-api.mustache @@ -173,7 +173,16 @@ func (c *{{classname}}Controller) {{nickname}}(w http.ResponseWriter, r *http.Re {{^isDouble}} {{^isLong}} {{^isInteger}} + {{^isEnumOrRef}} {{paramName}}Param := {{#routers}}{{#mux}}params["{{baseName}}"]{{/mux}}{{#chi}}chi.URLParam(r, "{{baseName}}"){{/chi}}{{/routers}} + {{/isEnumOrRef}} + {{#isEnumOrRef}} + {{paramName}}Param, err := New{{dataType}}FromValue({{#routers}}{{#mux}}params["{{baseName}}"]{{/mux}}{{#chi}}chi.URLParam(r, "{{baseName}}"){{/chi}}{{/routers}}) + if err != nil { + c.errorHandler(w, r, &ParsingError{Err: err}, nil) + return + } + {{/isEnumOrRef}} {{/isInteger}} {{/isLong}} {{/isDouble}} @@ -329,7 +338,27 @@ func (c *{{classname}}Controller) {{nickname}}(w http.ResponseWriter, r *http.Re {{^items.isDouble}} {{^items.isLong}} {{^items.isInteger}} - {{paramName}}Param := strings.Split(query.Get("{{baseName}}"), ",") + {{^items.isEnumRef}} + var {{paramName}}Param []string + if query.Has("{{baseName}}") { + {{paramName}}Param = strings.Split(query.Get("{{baseName}}"), ",") + } + {{/items.isEnumRef}} + {{#items.isEnumRef}} + var {{paramName}}Param []{{items.dataType}} + if query.Has("{{baseName}}") { + paramSplits := strings.Split(query.Get("{{baseName}}"), ",") + {{paramName}}Param = make([]{{items.dataType}}, 0, len(paramSplits)) + for _, param := range paramSplits { + paramEnum, err := New{{items.dataType}}FromValue(param) + if err != nil { + c.errorHandler(w, r, &ParsingError{Err: err}, nil) + return + } + {{paramName}}Param = append({{paramName}}Param, paramEnum) + } + } + {{/items.isEnumRef}} {{/items.isInteger}} {{/items.isLong}} {{/items.isDouble}} @@ -346,11 +375,42 @@ func (c *{{classname}}Controller) {{nickname}}(w http.ResponseWriter, r *http.Re {{#defaultValue}} {{paramName}}Param := "{{defaultValue}}" if query.Has("{{baseName}}") { - {{paramName}}Param = query.Get("{{baseName}}") + {{paramName}}Param = {{^isString}}{{dataType}}( {{/isString}}query.Get("{{baseName}}"){{^isString}} ){{/isString}} } {{/defaultValue}} {{^defaultValue}} + {{^required}} + var {{paramName}}Param {{dataType}} + if query.Has("{{baseName}}") { + {{^isEnumOrRef}} + {{paramName}}Param = query.Get("{{baseName}}") + {{/isEnumOrRef}} + {{#isEnumOrRef}} + var err error + {{paramName}}Param, err = New{{dataType}}FromValue(query.Get("{{baseName}}")) + if err != nil { + c.errorHandler(w, r, &ParsingError{Err: err}, nil) + return + } + {{/isEnumOrRef}} + } + {{/required}} + {{#required}} + {{^isEnumOrRef}} {{paramName}}Param := query.Get("{{baseName}}") + {{/isEnumOrRef}} + {{#isEnumOrRef}} + if !query.Has("{{baseName}}"){ + c.errorHandler(w, r, &RequiredError{"{{baseName}}"}, nil) + return + } + {{paramName}}Param, err := New{{dataType}}FromValue(query.Get("{{baseName}}")) + if err != nil { + c.errorHandler(w, r, &ParsingError{Err: err}, nil) + return + } + {{/isEnumOrRef}} + {{/required}} {{/defaultValue}} {{/isArray}} {{/isBoolean}} diff --git a/modules/openapi-generator/src/main/resources/go-server/model.mustache b/modules/openapi-generator/src/main/resources/go-server/model.mustache index f94a100a191..ce00067fc0b 100644 --- a/modules/openapi-generator/src/main/resources/go-server/model.mustache +++ b/modules/openapi-generator/src/main/resources/go-server/model.mustache @@ -17,7 +17,44 @@ const ( {{#enumClassPrefix}}{{{classname.toUpperCase}}}_{{/enumClassPrefix}}{{name}} {{{classname}}} = {{{value}}} {{/enumVars}} {{/allowableValues}} -){{/isEnum}}{{^isEnum}}{{#description}} +) + +// Allowed{{{classname}}}EnumValues is all the allowed values of {{{classname}}} enum +var Allowed{{{classname}}}EnumValues = []{{{classname}}}{ + {{#allowableValues}} + {{#enumVars}} + {{{value}}}, + {{/enumVars}} + {{/allowableValues}} +} + +// valid{{{classname}}}EnumValue provides a map of {{classname}}s for fast verification of use input +var valid{{{classname}}}EnumValues = map[{{{classname}}}]struct{}{ + {{#allowableValues}} + {{#enumVars}} + {{{value}}}: {}, + {{/enumVars}} + {{/allowableValues}} +} + +// IsValid return true if the value is valid for the enum, false otherwise +func (v {{{classname}}}) IsValid() bool { + _, ok := valid{{{classname}}}EnumValues[v] + return ok +} + +// New{{{classname}}}FromValue returns a pointer to a valid {{{classname}}} +// for the value passed as argument, or an error if the value passed is not allowed by the enum +func New{{{classname}}}FromValue(v {{{format}}}{{^format}}{{dataType}}{{/format}}) ({{{classname}}}, error) { + ev := {{{classname}}}(v) + if ev.IsValid() { + return ev, nil + } else { + return "", fmt.Errorf("invalid value '%v' for {{{classname}}}: valid values are %v", v, Allowed{{{classname}}}EnumValues) + } +} + +{{/isEnum}}{{^isEnum}}{{#description}} // {{classname}} - {{{description}}}{{/description}} type {{classname}} struct { {{#parent}} diff --git a/modules/openapi-generator/src/test/resources/3_0/go-server/petstore.yaml b/modules/openapi-generator/src/test/resources/3_0/go-server/petstore.yaml index 3a3af8e98a8..f28f075a495 100644 --- a/modules/openapi-generator/src/test/resources/3_0/go-server/petstore.yaml +++ b/modules/openapi-generator/src/test/resources/3_0/go-server/petstore.yaml @@ -157,6 +157,52 @@ paths: - petstore_auth: - 'read:pets' deprecated: true + '/pet/filterPets/{gender}': + get: + tags: + - pet + summary: Finds Pets + operationId: filterPetsByCategory + parameters: + - name: gender + in: path + required: true + schema: + $ref: '#/components/schemas/Gender' + - name: species + in: query + description: Species to filter by + required: true + style: form + explode: false + schema: + $ref: '#/components/schemas/Species' + - name: notSpecies + in: query + description: Species to omit from results + required: false + style: form + explode: false + schema: + type: array + items: + $ref: '#/components/schemas/Species' + responses: + '200': + description: successful operation + content: + application/xml: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + '400': + description: Invalid species value '/pet/{petId}': get: tags: @@ -851,6 +897,20 @@ components: - sold xml: name: Pet + Species: + title: The species of a pet + type: string + enum: + - cat + - dog + - fish + - goat + - pig + Gender: + type: string + enum: + - male + - female ApiResponse: title: An uploaded response description: Describes the result of uploading an image resource diff --git a/samples/openapi3/server/petstore/go/go-petstore/go/api_pet.go b/samples/openapi3/server/petstore/go/go-petstore/go/api_pet.go index 612040bb79c..d00438d9bfd 100644 --- a/samples/openapi3/server/petstore/go/go-petstore/go/api_pet.go +++ b/samples/openapi3/server/petstore/go/go-petstore/go/api_pet.go @@ -144,7 +144,10 @@ func (c *PetAPIController) DeletePet(w http.ResponseWriter, r *http.Request) { // FindPetsByStatus - Finds Pets by status func (c *PetAPIController) FindPetsByStatus(w http.ResponseWriter, r *http.Request) { query := r.URL.Query() - statusParam := strings.Split(query.Get("status"), ",") + var statusParam []string + if query.Has("status") { + statusParam = strings.Split(query.Get("status"), ",") + } result, err := c.service.FindPetsByStatus(r.Context(), statusParam) // If an error occurred, encode the error with the status code if err != nil { @@ -159,7 +162,10 @@ func (c *PetAPIController) FindPetsByStatus(w http.ResponseWriter, r *http.Reque // Deprecated func (c *PetAPIController) FindPetsByTags(w http.ResponseWriter, r *http.Request) { query := r.URL.Query() - tagsParam := strings.Split(query.Get("tags"), ",") + var tagsParam []string + if query.Has("tags") { + tagsParam = strings.Split(query.Get("tags"), ",") + } result, err := c.service.FindPetsByTags(r.Context(), tagsParam) // If an error occurred, encode the error with the status code if err != nil { diff --git a/samples/server/petstore/go-api-server/.openapi-generator/FILES b/samples/server/petstore/go-api-server/.openapi-generator/FILES index 4c3a2a3a7c7..2e3c628098c 100644 --- a/samples/server/petstore/go-api-server/.openapi-generator/FILES +++ b/samples/server/petstore/go-api-server/.openapi-generator/FILES @@ -16,10 +16,12 @@ go/logger.go go/model_an_object.go go/model_api_response.go go/model_category.go +go/model_gender.go go/model_order.go go/model_order_info.go go/model_pet.go go/model_special_info.go +go/model_species.go go/model_tag.go go/model_user.go go/routers.go diff --git a/samples/server/petstore/go-api-server/api/openapi.yaml b/samples/server/petstore/go-api-server/api/openapi.yaml index 0402307cbaf..88e07777510 100644 --- a/samples/server/petstore/go-api-server/api/openapi.yaml +++ b/samples/server/petstore/go-api-server/api/openapi.yaml @@ -158,6 +158,54 @@ paths: summary: Finds Pets by tags tags: - pet + /pet/filterPets/{gender}: + get: + operationId: filterPetsByCategory + parameters: + - explode: false + in: path + name: gender + required: true + schema: + $ref: '#/components/schemas/Gender' + style: simple + - description: Species to filter by + explode: false + in: query + name: species + required: true + schema: + $ref: '#/components/schemas/Species' + style: form + - description: Species to omit from results + explode: false + in: query + name: notSpecies + required: false + schema: + items: + $ref: '#/components/schemas/Species' + type: array + style: form + responses: + "200": + content: + application/xml: + schema: + items: + $ref: '#/components/schemas/Pet' + type: array + application/json: + schema: + items: + $ref: '#/components/schemas/Pet' + type: array + description: successful operation + "400": + description: Invalid species value + summary: Finds Pets + tags: + - pet /pet/{petId}: delete: description: "" @@ -1020,6 +1068,20 @@ components: type: object xml: name: Pet + Species: + enum: + - cat + - dog + - fish + - goat + - pig + title: The species of a pet + type: string + Gender: + enum: + - male + - female + type: string ApiResponse: description: Describes the result of uploading an image resource example: diff --git a/samples/server/petstore/go-api-server/go/api.go b/samples/server/petstore/go-api-server/go/api.go index 9edc08f180f..18ab08d8f26 100644 --- a/samples/server/petstore/go-api-server/go/api.go +++ b/samples/server/petstore/go-api-server/go/api.go @@ -23,6 +23,7 @@ import ( type PetAPIRouter interface { AddPet(http.ResponseWriter, *http.Request) DeletePet(http.ResponseWriter, *http.Request) + FilterPetsByCategory(http.ResponseWriter, *http.Request) FindPetsByStatus(http.ResponseWriter, *http.Request) // Deprecated FindPetsByTags(http.ResponseWriter, *http.Request) @@ -63,6 +64,7 @@ type UserAPIRouter interface { type PetAPIServicer interface { AddPet(context.Context, Pet) (ImplResponse, error) DeletePet(context.Context, int64, string) (ImplResponse, error) + FilterPetsByCategory(context.Context, Gender, Species, []Species) (ImplResponse, error) FindPetsByStatus(context.Context, []string) (ImplResponse, error) // Deprecated FindPetsByTags(context.Context, []string) (ImplResponse, error) diff --git a/samples/server/petstore/go-api-server/go/api_pet.go b/samples/server/petstore/go-api-server/go/api_pet.go index 87338f89b27..10ea4d6870c 100644 --- a/samples/server/petstore/go-api-server/go/api_pet.go +++ b/samples/server/petstore/go-api-server/go/api_pet.go @@ -60,6 +60,11 @@ func (c *PetAPIController) Routes() Routes { "/v2/pet/{petId}", c.DeletePet, }, + "FilterPetsByCategory": Route{ + strings.ToUpper("Get"), + "/v2/pet/filterPets/{gender}", + c.FilterPetsByCategory, + }, "FindPetsByStatus": Route{ strings.ToUpper("Get"), "/v2/pet/findByStatus", @@ -147,10 +152,54 @@ func (c *PetAPIController) DeletePet(w http.ResponseWriter, r *http.Request) { EncodeJSONResponse(result.Body, &result.Code, result.Headers, w) } +// FilterPetsByCategory - Finds Pets +func (c *PetAPIController) FilterPetsByCategory(w http.ResponseWriter, r *http.Request) { + params := mux.Vars(r) + query := r.URL.Query() + genderParam, err := NewGenderFromValue(params["gender"]) + if err != nil { + c.errorHandler(w, r, &ParsingError{Err: err}, nil) + return + } + if !query.Has("species"){ + c.errorHandler(w, r, &RequiredError{"species"}, nil) + return + } + speciesParam, err := NewSpeciesFromValue(query.Get("species")) + if err != nil { + c.errorHandler(w, r, &ParsingError{Err: err}, nil) + return + } + var notSpeciesParam []Species + if query.Has("notSpecies") { + paramSplits := strings.Split(query.Get("notSpecies"), ",") + notSpeciesParam = make([]Species, 0, len(paramSplits)) + for _, param := range paramSplits { + paramEnum, err := NewSpeciesFromValue(param) + if err != nil { + c.errorHandler(w, r, &ParsingError{Err: err}, nil) + return + } + notSpeciesParam = append(notSpeciesParam, paramEnum) + } + } + result, err := c.service.FilterPetsByCategory(r.Context(), genderParam, speciesParam, notSpeciesParam) + // If an error occurred, encode the error with the status code + if err != nil { + c.errorHandler(w, r, err, &result) + return + } + // If no error, encode the body and the result code + EncodeJSONResponse(result.Body, &result.Code, result.Headers, w) +} + // FindPetsByStatus - Finds Pets by status func (c *PetAPIController) FindPetsByStatus(w http.ResponseWriter, r *http.Request) { query := r.URL.Query() - statusParam := strings.Split(query.Get("status"), ",") + var statusParam []string + if query.Has("status") { + statusParam = strings.Split(query.Get("status"), ",") + } result, err := c.service.FindPetsByStatus(r.Context(), statusParam) // If an error occurred, encode the error with the status code if err != nil { @@ -165,7 +214,10 @@ func (c *PetAPIController) FindPetsByStatus(w http.ResponseWriter, r *http.Reque // Deprecated func (c *PetAPIController) FindPetsByTags(w http.ResponseWriter, r *http.Request) { query := r.URL.Query() - tagsParam := strings.Split(query.Get("tags"), ",") + var tagsParam []string + if query.Has("tags") { + tagsParam = strings.Split(query.Get("tags"), ",") + } result, err := c.service.FindPetsByTags(r.Context(), tagsParam) // If an error occurred, encode the error with the status code if err != nil { diff --git a/samples/server/petstore/go-api-server/go/api_pet_service.go b/samples/server/petstore/go-api-server/go/api_pet_service.go index d4470e51e9a..1d54529fb94 100644 --- a/samples/server/petstore/go-api-server/go/api_pet_service.go +++ b/samples/server/petstore/go-api-server/go/api_pet_service.go @@ -52,6 +52,20 @@ func (s *PetAPIService) DeletePet(ctx context.Context, petId int64, apiKey strin return Response(http.StatusNotImplemented, nil), errors.New("DeletePet method not implemented") } +// FilterPetsByCategory - Finds Pets +func (s *PetAPIService) FilterPetsByCategory(ctx context.Context, gender Gender, species Species, notSpecies []Species) (ImplResponse, error) { + // TODO - update FilterPetsByCategory with the required logic for this service method. + // Add api_pet_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation. + + // TODO: Uncomment the next line to return response Response(200, []Pet{}) or use other options such as http.Ok ... + // return Response(200, []Pet{}), nil + + // TODO: Uncomment the next line to return response Response(400, {}) or use other options such as http.Ok ... + // return Response(400, nil),nil + + return Response(http.StatusNotImplemented, nil), errors.New("FilterPetsByCategory method not implemented") +} + // FindPetsByStatus - Finds Pets by status func (s *PetAPIService) FindPetsByStatus(ctx context.Context, status []string) (ImplResponse, error) { // TODO - update FindPetsByStatus with the required logic for this service method. diff --git a/samples/server/petstore/go-api-server/go/model_gender.go b/samples/server/petstore/go-api-server/go/model_gender.go new file mode 100644 index 00000000000..16583a0c400 --- /dev/null +++ b/samples/server/petstore/go-api-server/go/model_gender.go @@ -0,0 +1,66 @@ +/* + * OpenAPI Petstore + * + * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + * + * API version: 1.0.0 + * Generated by: OpenAPI Generator (https://openapi-generator.tech) + */ + +package petstoreserver + + +import ( + "fmt" +) + + + +type Gender string + +// List of Gender +const ( + MALE Gender = "male" + FEMALE Gender = "female" +) + +// AllowedGenderEnumValues is all the allowed values of Gender enum +var AllowedGenderEnumValues = []Gender{ + "male", + "female", +} + +// validGenderEnumValue provides a map of Genders for fast verification of use input +var validGenderEnumValues = map[Gender]struct{}{ + "male": {}, + "female": {}, +} + +// IsValid return true if the value is valid for the enum, false otherwise +func (v Gender) IsValid() bool { + _, ok := validGenderEnumValues[v] + return ok +} + +// NewGenderFromValue returns a pointer to a valid Gender +// for the value passed as argument, or an error if the value passed is not allowed by the enum +func NewGenderFromValue(v string) (Gender, error) { + ev := Gender(v) + if ev.IsValid() { + return ev, nil + } else { + return "", fmt.Errorf("invalid value '%v' for Gender: valid values are %v", v, AllowedGenderEnumValues) + } +} + + + +// AssertGenderRequired checks if the required fields are not zero-ed +func AssertGenderRequired(obj Gender) error { + return nil +} + +// AssertGenderConstraints checks if the values respects the defined constraints +func AssertGenderConstraints(obj Gender) error { + return nil +} diff --git a/samples/server/petstore/go-api-server/go/model_species.go b/samples/server/petstore/go-api-server/go/model_species.go new file mode 100644 index 00000000000..4e6fc567e6a --- /dev/null +++ b/samples/server/petstore/go-api-server/go/model_species.go @@ -0,0 +1,75 @@ +/* + * OpenAPI Petstore + * + * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + * + * API version: 1.0.0 + * Generated by: OpenAPI Generator (https://openapi-generator.tech) + */ + +package petstoreserver + + +import ( + "fmt" +) + + + +type Species string + +// List of Species +const ( + CAT Species = "cat" + DOG Species = "dog" + FISH Species = "fish" + GOAT Species = "goat" + PIG Species = "pig" +) + +// AllowedSpeciesEnumValues is all the allowed values of Species enum +var AllowedSpeciesEnumValues = []Species{ + "cat", + "dog", + "fish", + "goat", + "pig", +} + +// validSpeciesEnumValue provides a map of Speciess for fast verification of use input +var validSpeciesEnumValues = map[Species]struct{}{ + "cat": {}, + "dog": {}, + "fish": {}, + "goat": {}, + "pig": {}, +} + +// IsValid return true if the value is valid for the enum, false otherwise +func (v Species) IsValid() bool { + _, ok := validSpeciesEnumValues[v] + return ok +} + +// NewSpeciesFromValue returns a pointer to a valid Species +// for the value passed as argument, or an error if the value passed is not allowed by the enum +func NewSpeciesFromValue(v string) (Species, error) { + ev := Species(v) + if ev.IsValid() { + return ev, nil + } else { + return "", fmt.Errorf("invalid value '%v' for Species: valid values are %v", v, AllowedSpeciesEnumValues) + } +} + + + +// AssertSpeciesRequired checks if the required fields are not zero-ed +func AssertSpeciesRequired(obj Species) error { + return nil +} + +// AssertSpeciesConstraints checks if the values respects the defined constraints +func AssertSpeciesConstraints(obj Species) error { + return nil +} diff --git a/samples/server/petstore/go-chi-server/.openapi-generator/FILES b/samples/server/petstore/go-chi-server/.openapi-generator/FILES index 4c3a2a3a7c7..2e3c628098c 100644 --- a/samples/server/petstore/go-chi-server/.openapi-generator/FILES +++ b/samples/server/petstore/go-chi-server/.openapi-generator/FILES @@ -16,10 +16,12 @@ go/logger.go go/model_an_object.go go/model_api_response.go go/model_category.go +go/model_gender.go go/model_order.go go/model_order_info.go go/model_pet.go go/model_special_info.go +go/model_species.go go/model_tag.go go/model_user.go go/routers.go diff --git a/samples/server/petstore/go-chi-server/api/openapi.yaml b/samples/server/petstore/go-chi-server/api/openapi.yaml index 0402307cbaf..88e07777510 100644 --- a/samples/server/petstore/go-chi-server/api/openapi.yaml +++ b/samples/server/petstore/go-chi-server/api/openapi.yaml @@ -158,6 +158,54 @@ paths: summary: Finds Pets by tags tags: - pet + /pet/filterPets/{gender}: + get: + operationId: filterPetsByCategory + parameters: + - explode: false + in: path + name: gender + required: true + schema: + $ref: '#/components/schemas/Gender' + style: simple + - description: Species to filter by + explode: false + in: query + name: species + required: true + schema: + $ref: '#/components/schemas/Species' + style: form + - description: Species to omit from results + explode: false + in: query + name: notSpecies + required: false + schema: + items: + $ref: '#/components/schemas/Species' + type: array + style: form + responses: + "200": + content: + application/xml: + schema: + items: + $ref: '#/components/schemas/Pet' + type: array + application/json: + schema: + items: + $ref: '#/components/schemas/Pet' + type: array + description: successful operation + "400": + description: Invalid species value + summary: Finds Pets + tags: + - pet /pet/{petId}: delete: description: "" @@ -1020,6 +1068,20 @@ components: type: object xml: name: Pet + Species: + enum: + - cat + - dog + - fish + - goat + - pig + title: The species of a pet + type: string + Gender: + enum: + - male + - female + type: string ApiResponse: description: Describes the result of uploading an image resource example: diff --git a/samples/server/petstore/go-chi-server/go/api.go b/samples/server/petstore/go-chi-server/go/api.go index 9edc08f180f..18ab08d8f26 100644 --- a/samples/server/petstore/go-chi-server/go/api.go +++ b/samples/server/petstore/go-chi-server/go/api.go @@ -23,6 +23,7 @@ import ( type PetAPIRouter interface { AddPet(http.ResponseWriter, *http.Request) DeletePet(http.ResponseWriter, *http.Request) + FilterPetsByCategory(http.ResponseWriter, *http.Request) FindPetsByStatus(http.ResponseWriter, *http.Request) // Deprecated FindPetsByTags(http.ResponseWriter, *http.Request) @@ -63,6 +64,7 @@ type UserAPIRouter interface { type PetAPIServicer interface { AddPet(context.Context, Pet) (ImplResponse, error) DeletePet(context.Context, int64, string) (ImplResponse, error) + FilterPetsByCategory(context.Context, Gender, Species, []Species) (ImplResponse, error) FindPetsByStatus(context.Context, []string) (ImplResponse, error) // Deprecated FindPetsByTags(context.Context, []string) (ImplResponse, error) diff --git a/samples/server/petstore/go-chi-server/go/api_pet.go b/samples/server/petstore/go-chi-server/go/api_pet.go index 43f67846262..e780ab1af29 100644 --- a/samples/server/petstore/go-chi-server/go/api_pet.go +++ b/samples/server/petstore/go-chi-server/go/api_pet.go @@ -60,6 +60,11 @@ func (c *PetAPIController) Routes() Routes { "/v2/pet/{petId}", c.DeletePet, }, + "FilterPetsByCategory": Route{ + strings.ToUpper("Get"), + "/v2/pet/filterPets/{gender}", + c.FilterPetsByCategory, + }, "FindPetsByStatus": Route{ strings.ToUpper("Get"), "/v2/pet/findByStatus", @@ -146,10 +151,53 @@ func (c *PetAPIController) DeletePet(w http.ResponseWriter, r *http.Request) { EncodeJSONResponse(result.Body, &result.Code, result.Headers, w) } +// FilterPetsByCategory - Finds Pets +func (c *PetAPIController) FilterPetsByCategory(w http.ResponseWriter, r *http.Request) { + query := r.URL.Query() + genderParam, err := NewGenderFromValue(chi.URLParam(r, "gender")) + if err != nil { + c.errorHandler(w, r, &ParsingError{Err: err}, nil) + return + } + if !query.Has("species"){ + c.errorHandler(w, r, &RequiredError{"species"}, nil) + return + } + speciesParam, err := NewSpeciesFromValue(query.Get("species")) + if err != nil { + c.errorHandler(w, r, &ParsingError{Err: err}, nil) + return + } + var notSpeciesParam []Species + if query.Has("notSpecies") { + paramSplits := strings.Split(query.Get("notSpecies"), ",") + notSpeciesParam = make([]Species, 0, len(paramSplits)) + for _, param := range paramSplits { + paramEnum, err := NewSpeciesFromValue(param) + if err != nil { + c.errorHandler(w, r, &ParsingError{Err: err}, nil) + return + } + notSpeciesParam = append(notSpeciesParam, paramEnum) + } + } + result, err := c.service.FilterPetsByCategory(r.Context(), genderParam, speciesParam, notSpeciesParam) + // If an error occurred, encode the error with the status code + if err != nil { + c.errorHandler(w, r, err, &result) + return + } + // If no error, encode the body and the result code + EncodeJSONResponse(result.Body, &result.Code, result.Headers, w) +} + // FindPetsByStatus - Finds Pets by status func (c *PetAPIController) FindPetsByStatus(w http.ResponseWriter, r *http.Request) { query := r.URL.Query() - statusParam := strings.Split(query.Get("status"), ",") + var statusParam []string + if query.Has("status") { + statusParam = strings.Split(query.Get("status"), ",") + } result, err := c.service.FindPetsByStatus(r.Context(), statusParam) // If an error occurred, encode the error with the status code if err != nil { @@ -164,7 +212,10 @@ func (c *PetAPIController) FindPetsByStatus(w http.ResponseWriter, r *http.Reque // Deprecated func (c *PetAPIController) FindPetsByTags(w http.ResponseWriter, r *http.Request) { query := r.URL.Query() - tagsParam := strings.Split(query.Get("tags"), ",") + var tagsParam []string + if query.Has("tags") { + tagsParam = strings.Split(query.Get("tags"), ",") + } result, err := c.service.FindPetsByTags(r.Context(), tagsParam) // If an error occurred, encode the error with the status code if err != nil { diff --git a/samples/server/petstore/go-chi-server/go/api_pet_service.go b/samples/server/petstore/go-chi-server/go/api_pet_service.go index d4470e51e9a..1d54529fb94 100644 --- a/samples/server/petstore/go-chi-server/go/api_pet_service.go +++ b/samples/server/petstore/go-chi-server/go/api_pet_service.go @@ -52,6 +52,20 @@ func (s *PetAPIService) DeletePet(ctx context.Context, petId int64, apiKey strin return Response(http.StatusNotImplemented, nil), errors.New("DeletePet method not implemented") } +// FilterPetsByCategory - Finds Pets +func (s *PetAPIService) FilterPetsByCategory(ctx context.Context, gender Gender, species Species, notSpecies []Species) (ImplResponse, error) { + // TODO - update FilterPetsByCategory with the required logic for this service method. + // Add api_pet_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation. + + // TODO: Uncomment the next line to return response Response(200, []Pet{}) or use other options such as http.Ok ... + // return Response(200, []Pet{}), nil + + // TODO: Uncomment the next line to return response Response(400, {}) or use other options such as http.Ok ... + // return Response(400, nil),nil + + return Response(http.StatusNotImplemented, nil), errors.New("FilterPetsByCategory method not implemented") +} + // FindPetsByStatus - Finds Pets by status func (s *PetAPIService) FindPetsByStatus(ctx context.Context, status []string) (ImplResponse, error) { // TODO - update FindPetsByStatus with the required logic for this service method. diff --git a/samples/server/petstore/go-chi-server/go/model_gender.go b/samples/server/petstore/go-chi-server/go/model_gender.go new file mode 100644 index 00000000000..16583a0c400 --- /dev/null +++ b/samples/server/petstore/go-chi-server/go/model_gender.go @@ -0,0 +1,66 @@ +/* + * OpenAPI Petstore + * + * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + * + * API version: 1.0.0 + * Generated by: OpenAPI Generator (https://openapi-generator.tech) + */ + +package petstoreserver + + +import ( + "fmt" +) + + + +type Gender string + +// List of Gender +const ( + MALE Gender = "male" + FEMALE Gender = "female" +) + +// AllowedGenderEnumValues is all the allowed values of Gender enum +var AllowedGenderEnumValues = []Gender{ + "male", + "female", +} + +// validGenderEnumValue provides a map of Genders for fast verification of use input +var validGenderEnumValues = map[Gender]struct{}{ + "male": {}, + "female": {}, +} + +// IsValid return true if the value is valid for the enum, false otherwise +func (v Gender) IsValid() bool { + _, ok := validGenderEnumValues[v] + return ok +} + +// NewGenderFromValue returns a pointer to a valid Gender +// for the value passed as argument, or an error if the value passed is not allowed by the enum +func NewGenderFromValue(v string) (Gender, error) { + ev := Gender(v) + if ev.IsValid() { + return ev, nil + } else { + return "", fmt.Errorf("invalid value '%v' for Gender: valid values are %v", v, AllowedGenderEnumValues) + } +} + + + +// AssertGenderRequired checks if the required fields are not zero-ed +func AssertGenderRequired(obj Gender) error { + return nil +} + +// AssertGenderConstraints checks if the values respects the defined constraints +func AssertGenderConstraints(obj Gender) error { + return nil +} diff --git a/samples/server/petstore/go-chi-server/go/model_species.go b/samples/server/petstore/go-chi-server/go/model_species.go new file mode 100644 index 00000000000..4e6fc567e6a --- /dev/null +++ b/samples/server/petstore/go-chi-server/go/model_species.go @@ -0,0 +1,75 @@ +/* + * OpenAPI Petstore + * + * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + * + * API version: 1.0.0 + * Generated by: OpenAPI Generator (https://openapi-generator.tech) + */ + +package petstoreserver + + +import ( + "fmt" +) + + + +type Species string + +// List of Species +const ( + CAT Species = "cat" + DOG Species = "dog" + FISH Species = "fish" + GOAT Species = "goat" + PIG Species = "pig" +) + +// AllowedSpeciesEnumValues is all the allowed values of Species enum +var AllowedSpeciesEnumValues = []Species{ + "cat", + "dog", + "fish", + "goat", + "pig", +} + +// validSpeciesEnumValue provides a map of Speciess for fast verification of use input +var validSpeciesEnumValues = map[Species]struct{}{ + "cat": {}, + "dog": {}, + "fish": {}, + "goat": {}, + "pig": {}, +} + +// IsValid return true if the value is valid for the enum, false otherwise +func (v Species) IsValid() bool { + _, ok := validSpeciesEnumValues[v] + return ok +} + +// NewSpeciesFromValue returns a pointer to a valid Species +// for the value passed as argument, or an error if the value passed is not allowed by the enum +func NewSpeciesFromValue(v string) (Species, error) { + ev := Species(v) + if ev.IsValid() { + return ev, nil + } else { + return "", fmt.Errorf("invalid value '%v' for Species: valid values are %v", v, AllowedSpeciesEnumValues) + } +} + + + +// AssertSpeciesRequired checks if the required fields are not zero-ed +func AssertSpeciesRequired(obj Species) error { + return nil +} + +// AssertSpeciesConstraints checks if the values respects the defined constraints +func AssertSpeciesConstraints(obj Species) error { + return nil +}