From c79d056935e35acd287c04188f551699dcb45fc4 Mon Sep 17 00:00:00 2001 From: William Cheng Date: Mon, 5 Apr 2021 16:27:41 +0800 Subject: [PATCH] Allow to specify response headers (needed for redirecting clients) (#9170) * Allow to specify response headers (needed for redirecting clients) (#8148) Co-authored-by: Bernardo Pastorelli <13519917+randomswdev@users.noreply.github.com> * add addResponseHeaders option * enable addResponseHeaders * fix comma Co-authored-by: randomswdev Co-authored-by: Bernardo Pastorelli <13519917+randomswdev@users.noreply.github.com> --- bin/configs/go-server-go-api-server.yaml | 1 + docs/generators/go-server.md | 1 + .../codegen/languages/GoServerCodegen.java | 18 +++++++++++ .../go-server/controller-api.mustache | 4 +-- .../main/resources/go-server/helpers.mustache | 18 ++++++++++- .../main/resources/go-server/impl.mustache | 5 ++- .../main/resources/go-server/routers.mustache | 15 ++++++++- .../petstore/go-api-server/go/api_pet.go | 32 +++++++++---------- .../petstore/go-api-server/go/api_store.go | 16 +++++----- .../petstore/go-api-server/go/api_user.go | 32 +++++++++---------- .../petstore/go-api-server/go/helpers.go | 14 +++++++- .../server/petstore/go-api-server/go/impl.go | 3 +- .../petstore/go-api-server/go/routers.go | 2 +- 13 files changed, 113 insertions(+), 48 deletions(-) diff --git a/bin/configs/go-server-go-api-server.yaml b/bin/configs/go-server-go-api-server.yaml index 6446d212a35..7fb761639b2 100644 --- a/bin/configs/go-server-go-api-server.yaml +++ b/bin/configs/go-server-go-api-server.yaml @@ -5,3 +5,4 @@ templateDir: modules/openapi-generator/src/main/resources/go-server additionalProperties: hideGenerationTimestamp: "true" packageName: petstoreserver + addResponseHeaders: true diff --git a/docs/generators/go-server.md b/docs/generators/go-server.md index e0abd3de52c..36ac78aea6d 100644 --- a/docs/generators/go-server.md +++ b/docs/generators/go-server.md @@ -7,6 +7,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl | Option | Description | Values | Default | | ------ | ----------- | ------ | ------- | +|addResponseHeaders|To include response headers in ImplResponse| |false| |enumClassPrefix|Prefix enum with class name| |false| |featureCORS|Enable Cross-Origin Resource Sharing middleware| |false| |hideGenerationTimestamp|Hides the generation timestamp when files are generated.| |true| 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 2e08cb6f39d..df37293a02f 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 @@ -37,6 +37,7 @@ public class GoServerCodegen extends AbstractGoCodegen { protected String projectName = "openapi-server"; protected String sourceFolder = "go"; protected Boolean corsFeatureEnabled = false; + protected Boolean addResponseHeaders = false; public GoServerCodegen() { @@ -80,6 +81,12 @@ public class GoServerCodegen extends AbstractGoCodegen { cliOptions.add(CliOption.newBoolean(CodegenConstants.ENUM_CLASS_PREFIX, CodegenConstants.ENUM_CLASS_PREFIX_DESC)); + // option to include headers in the response + CliOption optAddResponseHeaders = new CliOption("addResponseHeaders", "To include response headers in ImplResponse"); + optAddResponseHeaders.setType("bool"); + optAddResponseHeaders.defaultValue(addResponseHeaders.toString()); + cliOptions.add(optAddResponseHeaders); + /* * Models. You can write model files using the modelTemplateFiles map. * if you want to create one template for file, you can do so here. @@ -172,12 +179,19 @@ public class GoServerCodegen extends AbstractGoCodegen { } else { additionalProperties.put("serverPort", serverPort); } + if (additionalProperties.containsKey("featureCORS")) { this.setFeatureCORS(convertPropertyToBooleanAndWriteBack("featureCORS")); } else { additionalProperties.put("featureCORS", corsFeatureEnabled); } + if (additionalProperties.containsKey("addResponseHeaders")) { + this.setAddResponseHeaders(convertPropertyToBooleanAndWriteBack("addResponseHeaders")); + } else { + additionalProperties.put("addResponseHeaders", addResponseHeaders); + } + if (additionalProperties.containsKey(CodegenConstants.ENUM_CLASS_PREFIX)) { setEnumClassPrefix(Boolean.parseBoolean(additionalProperties.get(CodegenConstants.ENUM_CLASS_PREFIX).toString())); if (enumClassPrefix) { @@ -314,4 +328,8 @@ public class GoServerCodegen extends AbstractGoCodegen { public void setFeatureCORS(Boolean featureCORS) { this.corsFeatureEnabled = featureCORS; } + + public void setAddResponseHeaders(Boolean addResponseHeaders) { + this.addResponseHeaders = addResponseHeaders; + } } 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 7d321a03efe..e5bd38f9624 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 @@ -95,10 +95,10 @@ func (c *{{classname}}Controller) {{nickname}}(w http.ResponseWriter, r *http.Re result, err := c.service.{{nickname}}(r.Context(){{#allParams}}, {{#isBodyParam}}*{{/isBodyParam}}{{paramName}}{{/allParams}}) //If an error occured, encode the error with the status code if err != nil { - EncodeJSONResponse(err.Error(), &result.Code, w) + EncodeJSONResponse(err.Error(), &result.Code,{{#addResponseHeaders}} result.Headers,{{/addResponseHeaders}} w) return } //If no error, encode the body and the result code - EncodeJSONResponse(result.Body, &result.Code, w) + EncodeJSONResponse(result.Body, &result.Code,{{#addResponseHeaders}} result.Headers,{{/addResponseHeaders}} w) }{{/operation}}{{/operations}} diff --git a/modules/openapi-generator/src/main/resources/go-server/helpers.mustache b/modules/openapi-generator/src/main/resources/go-server/helpers.mustache index 2441678ab3b..13115656bc0 100644 --- a/modules/openapi-generator/src/main/resources/go-server/helpers.mustache +++ b/modules/openapi-generator/src/main/resources/go-server/helpers.mustache @@ -3,6 +3,22 @@ package {{packageName}} //Response return a ImplResponse struct filled func Response(code int, body interface{}) ImplResponse { - return ImplResponse{Code: code, Body: body} + return ImplResponse { + Code: code, + {{#addResponseHeaders}} + Headers: nil, + {{/addResponseHeaders}} + Body: body, + } } +{{#addResponseHeaders}} +//ResponseWithHeaders return a ImplResponse struct filled, including headers +func ResponseWithHeaders(code int, headers map[string][]string, body interface{}) ImplResponse { + return ImplResponse { + Code: code, + Headers: headers, + Body: body, + } +} +{{/addResponseHeaders}} diff --git a/modules/openapi-generator/src/main/resources/go-server/impl.mustache b/modules/openapi-generator/src/main/resources/go-server/impl.mustache index 3333cdecdc2..48d5a3e5e5c 100644 --- a/modules/openapi-generator/src/main/resources/go-server/impl.mustache +++ b/modules/openapi-generator/src/main/resources/go-server/impl.mustache @@ -4,5 +4,8 @@ package {{packageName}} //Implementation response defines an error code with the associated body type ImplResponse struct { Code int + {{#addResponseHeaders}} + Headers map[string][]string + {{/addResponseHeaders}} Body interface{} -} \ No newline at end of file +} diff --git a/modules/openapi-generator/src/main/resources/go-server/routers.mustache b/modules/openapi-generator/src/main/resources/go-server/routers.mustache index 6338eecd2e5..63d2f3efbfa 100644 --- a/modules/openapi-generator/src/main/resources/go-server/routers.mustache +++ b/modules/openapi-generator/src/main/resources/go-server/routers.mustache @@ -54,8 +54,21 @@ func NewRouter(routers ...Router) *mux.Router { } // EncodeJSONResponse uses the json encoder to write an interface to the http response with an optional status code -func EncodeJSONResponse(i interface{}, status *int, w http.ResponseWriter) error { +func EncodeJSONResponse(i interface{}, status *int,{{#addResponseHeaders}} headers map[string][]string,{{/addResponseHeaders}} w http.ResponseWriter) error { + {{#addResponseHeader}} + wHeader := w.Header() + if headers != nil { + for key, values := range headers { + for _, value := range values { + wHeader.Add(key, value) + } + } + } + wHeader.Set("Content-Type", "application/json; charset=UTF-8") + {{/addResponseHeader}} + {{^addResponseHeader}} w.Header().Set("Content-Type", "application/json; charset=UTF-8") + {{/addResponseHeader}} if status != nil { w.WriteHeader(*status) } else { 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 9cb0eb26d2c..e41b068d554 100644 --- a/samples/server/petstore/go-api-server/go/api_pet.go +++ b/samples/server/petstore/go-api-server/go/api_pet.go @@ -92,11 +92,11 @@ func (c *PetApiController) AddPet(w http.ResponseWriter, r *http.Request) { result, err := c.service.AddPet(r.Context(), *pet) //If an error occured, encode the error with the status code if err != nil { - EncodeJSONResponse(err.Error(), &result.Code, w) + EncodeJSONResponse(err.Error(), &result.Code, result.Headers, w) return } //If no error, encode the body and the result code - EncodeJSONResponse(result.Body, &result.Code, w) + EncodeJSONResponse(result.Body, &result.Code, result.Headers, w) } @@ -112,11 +112,11 @@ func (c *PetApiController) DeletePet(w http.ResponseWriter, r *http.Request) { result, err := c.service.DeletePet(r.Context(), petId, apiKey) //If an error occured, encode the error with the status code if err != nil { - EncodeJSONResponse(err.Error(), &result.Code, w) + EncodeJSONResponse(err.Error(), &result.Code, result.Headers, w) return } //If no error, encode the body and the result code - EncodeJSONResponse(result.Body, &result.Code, w) + EncodeJSONResponse(result.Body, &result.Code, result.Headers, w) } @@ -127,11 +127,11 @@ func (c *PetApiController) FindPetsByStatus(w http.ResponseWriter, r *http.Reque result, err := c.service.FindPetsByStatus(r.Context(), status) //If an error occured, encode the error with the status code if err != nil { - EncodeJSONResponse(err.Error(), &result.Code, w) + EncodeJSONResponse(err.Error(), &result.Code, result.Headers, w) return } //If no error, encode the body and the result code - EncodeJSONResponse(result.Body, &result.Code, w) + EncodeJSONResponse(result.Body, &result.Code, result.Headers, w) } @@ -142,11 +142,11 @@ func (c *PetApiController) FindPetsByTags(w http.ResponseWriter, r *http.Request result, err := c.service.FindPetsByTags(r.Context(), tags) //If an error occured, encode the error with the status code if err != nil { - EncodeJSONResponse(err.Error(), &result.Code, w) + EncodeJSONResponse(err.Error(), &result.Code, result.Headers, w) return } //If no error, encode the body and the result code - EncodeJSONResponse(result.Body, &result.Code, w) + EncodeJSONResponse(result.Body, &result.Code, result.Headers, w) } @@ -161,11 +161,11 @@ func (c *PetApiController) GetPetById(w http.ResponseWriter, r *http.Request) { result, err := c.service.GetPetById(r.Context(), petId) //If an error occured, encode the error with the status code if err != nil { - EncodeJSONResponse(err.Error(), &result.Code, w) + EncodeJSONResponse(err.Error(), &result.Code, result.Headers, w) return } //If no error, encode the body and the result code - EncodeJSONResponse(result.Body, &result.Code, w) + EncodeJSONResponse(result.Body, &result.Code, result.Headers, w) } @@ -180,11 +180,11 @@ func (c *PetApiController) UpdatePet(w http.ResponseWriter, r *http.Request) { result, err := c.service.UpdatePet(r.Context(), *pet) //If an error occured, encode the error with the status code if err != nil { - EncodeJSONResponse(err.Error(), &result.Code, w) + EncodeJSONResponse(err.Error(), &result.Code, result.Headers, w) return } //If no error, encode the body and the result code - EncodeJSONResponse(result.Body, &result.Code, w) + EncodeJSONResponse(result.Body, &result.Code, result.Headers, w) } @@ -207,11 +207,11 @@ func (c *PetApiController) UpdatePetWithForm(w http.ResponseWriter, r *http.Requ result, err := c.service.UpdatePetWithForm(r.Context(), petId, name, status) //If an error occured, encode the error with the status code if err != nil { - EncodeJSONResponse(err.Error(), &result.Code, w) + EncodeJSONResponse(err.Error(), &result.Code, result.Headers, w) return } //If no error, encode the body and the result code - EncodeJSONResponse(result.Body, &result.Code, w) + EncodeJSONResponse(result.Body, &result.Code, result.Headers, w) } @@ -239,10 +239,10 @@ func (c *PetApiController) UploadFile(w http.ResponseWriter, r *http.Request) { result, err := c.service.UploadFile(r.Context(), petId, additionalMetadata, file) //If an error occured, encode the error with the status code if err != nil { - EncodeJSONResponse(err.Error(), &result.Code, w) + EncodeJSONResponse(err.Error(), &result.Code, result.Headers, w) return } //If no error, encode the body and the result code - EncodeJSONResponse(result.Body, &result.Code, w) + EncodeJSONResponse(result.Body, &result.Code, result.Headers, w) } diff --git a/samples/server/petstore/go-api-server/go/api_store.go b/samples/server/petstore/go-api-server/go/api_store.go index 9b1fc198333..48eff337b38 100644 --- a/samples/server/petstore/go-api-server/go/api_store.go +++ b/samples/server/petstore/go-api-server/go/api_store.go @@ -64,11 +64,11 @@ func (c *StoreApiController) DeleteOrder(w http.ResponseWriter, r *http.Request) result, err := c.service.DeleteOrder(r.Context(), orderId) //If an error occured, encode the error with the status code if err != nil { - EncodeJSONResponse(err.Error(), &result.Code, w) + EncodeJSONResponse(err.Error(), &result.Code, result.Headers, w) return } //If no error, encode the body and the result code - EncodeJSONResponse(result.Body, &result.Code, w) + EncodeJSONResponse(result.Body, &result.Code, result.Headers, w) } @@ -77,11 +77,11 @@ func (c *StoreApiController) GetInventory(w http.ResponseWriter, r *http.Request result, err := c.service.GetInventory(r.Context()) //If an error occured, encode the error with the status code if err != nil { - EncodeJSONResponse(err.Error(), &result.Code, w) + EncodeJSONResponse(err.Error(), &result.Code, result.Headers, w) return } //If no error, encode the body and the result code - EncodeJSONResponse(result.Body, &result.Code, w) + EncodeJSONResponse(result.Body, &result.Code, result.Headers, w) } @@ -96,11 +96,11 @@ func (c *StoreApiController) GetOrderById(w http.ResponseWriter, r *http.Request result, err := c.service.GetOrderById(r.Context(), orderId) //If an error occured, encode the error with the status code if err != nil { - EncodeJSONResponse(err.Error(), &result.Code, w) + EncodeJSONResponse(err.Error(), &result.Code, result.Headers, w) return } //If no error, encode the body and the result code - EncodeJSONResponse(result.Body, &result.Code, w) + EncodeJSONResponse(result.Body, &result.Code, result.Headers, w) } @@ -115,10 +115,10 @@ func (c *StoreApiController) PlaceOrder(w http.ResponseWriter, r *http.Request) result, err := c.service.PlaceOrder(r.Context(), *order) //If an error occured, encode the error with the status code if err != nil { - EncodeJSONResponse(err.Error(), &result.Code, w) + EncodeJSONResponse(err.Error(), &result.Code, result.Headers, w) return } //If no error, encode the body and the result code - EncodeJSONResponse(result.Body, &result.Code, w) + EncodeJSONResponse(result.Body, &result.Code, result.Headers, w) } diff --git a/samples/server/petstore/go-api-server/go/api_user.go b/samples/server/petstore/go-api-server/go/api_user.go index 3d927df85d4..0fb20d4ef12 100644 --- a/samples/server/petstore/go-api-server/go/api_user.go +++ b/samples/server/petstore/go-api-server/go/api_user.go @@ -92,11 +92,11 @@ func (c *UserApiController) CreateUser(w http.ResponseWriter, r *http.Request) { result, err := c.service.CreateUser(r.Context(), *user) //If an error occured, encode the error with the status code if err != nil { - EncodeJSONResponse(err.Error(), &result.Code, w) + EncodeJSONResponse(err.Error(), &result.Code, result.Headers, w) return } //If no error, encode the body and the result code - EncodeJSONResponse(result.Body, &result.Code, w) + EncodeJSONResponse(result.Body, &result.Code, result.Headers, w) } @@ -111,11 +111,11 @@ func (c *UserApiController) CreateUsersWithArrayInput(w http.ResponseWriter, r * result, err := c.service.CreateUsersWithArrayInput(r.Context(), *user) //If an error occured, encode the error with the status code if err != nil { - EncodeJSONResponse(err.Error(), &result.Code, w) + EncodeJSONResponse(err.Error(), &result.Code, result.Headers, w) return } //If no error, encode the body and the result code - EncodeJSONResponse(result.Body, &result.Code, w) + EncodeJSONResponse(result.Body, &result.Code, result.Headers, w) } @@ -130,11 +130,11 @@ func (c *UserApiController) CreateUsersWithListInput(w http.ResponseWriter, r *h result, err := c.service.CreateUsersWithListInput(r.Context(), *user) //If an error occured, encode the error with the status code if err != nil { - EncodeJSONResponse(err.Error(), &result.Code, w) + EncodeJSONResponse(err.Error(), &result.Code, result.Headers, w) return } //If no error, encode the body and the result code - EncodeJSONResponse(result.Body, &result.Code, w) + EncodeJSONResponse(result.Body, &result.Code, result.Headers, w) } @@ -145,11 +145,11 @@ func (c *UserApiController) DeleteUser(w http.ResponseWriter, r *http.Request) { result, err := c.service.DeleteUser(r.Context(), username) //If an error occured, encode the error with the status code if err != nil { - EncodeJSONResponse(err.Error(), &result.Code, w) + EncodeJSONResponse(err.Error(), &result.Code, result.Headers, w) return } //If no error, encode the body and the result code - EncodeJSONResponse(result.Body, &result.Code, w) + EncodeJSONResponse(result.Body, &result.Code, result.Headers, w) } @@ -160,11 +160,11 @@ func (c *UserApiController) GetUserByName(w http.ResponseWriter, r *http.Request result, err := c.service.GetUserByName(r.Context(), username) //If an error occured, encode the error with the status code if err != nil { - EncodeJSONResponse(err.Error(), &result.Code, w) + EncodeJSONResponse(err.Error(), &result.Code, result.Headers, w) return } //If no error, encode the body and the result code - EncodeJSONResponse(result.Body, &result.Code, w) + EncodeJSONResponse(result.Body, &result.Code, result.Headers, w) } @@ -176,11 +176,11 @@ func (c *UserApiController) LoginUser(w http.ResponseWriter, r *http.Request) { result, err := c.service.LoginUser(r.Context(), username, password) //If an error occured, encode the error with the status code if err != nil { - EncodeJSONResponse(err.Error(), &result.Code, w) + EncodeJSONResponse(err.Error(), &result.Code, result.Headers, w) return } //If no error, encode the body and the result code - EncodeJSONResponse(result.Body, &result.Code, w) + EncodeJSONResponse(result.Body, &result.Code, result.Headers, w) } @@ -189,11 +189,11 @@ func (c *UserApiController) LogoutUser(w http.ResponseWriter, r *http.Request) { result, err := c.service.LogoutUser(r.Context()) //If an error occured, encode the error with the status code if err != nil { - EncodeJSONResponse(err.Error(), &result.Code, w) + EncodeJSONResponse(err.Error(), &result.Code, result.Headers, w) return } //If no error, encode the body and the result code - EncodeJSONResponse(result.Body, &result.Code, w) + EncodeJSONResponse(result.Body, &result.Code, result.Headers, w) } @@ -210,10 +210,10 @@ func (c *UserApiController) UpdateUser(w http.ResponseWriter, r *http.Request) { result, err := c.service.UpdateUser(r.Context(), username, *user) //If an error occured, encode the error with the status code if err != nil { - EncodeJSONResponse(err.Error(), &result.Code, w) + EncodeJSONResponse(err.Error(), &result.Code, result.Headers, w) return } //If no error, encode the body and the result code - EncodeJSONResponse(result.Body, &result.Code, w) + EncodeJSONResponse(result.Body, &result.Code, result.Headers, w) } diff --git a/samples/server/petstore/go-api-server/go/helpers.go b/samples/server/petstore/go-api-server/go/helpers.go index 449cbb7be35..179ee893f7f 100644 --- a/samples/server/petstore/go-api-server/go/helpers.go +++ b/samples/server/petstore/go-api-server/go/helpers.go @@ -11,6 +11,18 @@ package petstoreserver //Response return a ImplResponse struct filled func Response(code int, body interface{}) ImplResponse { - return ImplResponse{Code: code, Body: body} + return ImplResponse { + Code: code, + Headers: nil, + Body: body, + } } +//ResponseWithHeaders return a ImplResponse struct filled, including headers +func ResponseWithHeaders(code int, headers map[string][]string, body interface{}) ImplResponse { + return ImplResponse { + Code: code, + Headers: headers, + Body: body, + } +} diff --git a/samples/server/petstore/go-api-server/go/impl.go b/samples/server/petstore/go-api-server/go/impl.go index 034db6e1cda..1da96f41252 100644 --- a/samples/server/petstore/go-api-server/go/impl.go +++ b/samples/server/petstore/go-api-server/go/impl.go @@ -12,5 +12,6 @@ package petstoreserver //Implementation response defines an error code with the associated body type ImplResponse struct { Code int + Headers map[string][]string Body interface{} -} \ No newline at end of file +} diff --git a/samples/server/petstore/go-api-server/go/routers.go b/samples/server/petstore/go-api-server/go/routers.go index baf545767bf..ab698786df1 100644 --- a/samples/server/petstore/go-api-server/go/routers.go +++ b/samples/server/petstore/go-api-server/go/routers.go @@ -56,7 +56,7 @@ func NewRouter(routers ...Router) *mux.Router { } // EncodeJSONResponse uses the json encoder to write an interface to the http response with an optional status code -func EncodeJSONResponse(i interface{}, status *int, w http.ResponseWriter) error { +func EncodeJSONResponse(i interface{}, status *int, headers map[string][]string, w http.ResponseWriter) error { w.Header().Set("Content-Type", "application/json; charset=UTF-8") if status != nil { w.WriteHeader(*status)