[go-server] Enhance Go API server with interfaces router binding and services (#4038)

* Enhance go api server with interfaces router binding and services

Enhance the default go api server generation to define interfaces for an API's routes and services. Handle an endpoint's http binding in the generated router and the skeleton for the service logic in an API service.

* Include interface documentation in Go Server generation.
This commit is contained in:
Jesse Michael
2019-10-19 08:32:52 -07:00
committed by William Cheng
parent dd64241f8f
commit 0abb910dbc
15 changed files with 1083 additions and 257 deletions

View File

@@ -19,6 +19,8 @@ package org.openapitools.codegen.languages;
import org.openapitools.codegen.CliOption;
import org.openapitools.codegen.CodegenConstants;
import org.openapitools.codegen.CodegenOperation;
import org.openapitools.codegen.CodegenParameter;
import org.openapitools.codegen.CodegenType;
import org.openapitools.codegen.SupportingFile;
import org.slf4j.Logger;
@@ -26,6 +28,8 @@ import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class GoServerCodegen extends AbstractGoCodegen {
@@ -70,6 +74,15 @@ public class GoServerCodegen extends AbstractGoCodegen {
"controller-api.mustache", // the template to use
".go"); // the extension for each file to write
/*
* Service templates. You can write services for each Api file with the apiTemplateFiles map.
These services are skeletons built to implement the logic of your api using the
expected parameters and response.
*/
apiTemplateFiles.put(
"service.mustache", // the template to use
"_service.go"); // the extension for each file to write
/*
* Template Location. This is the location which templates will be read from. The generator
* will use the resource stream to attempt to read the templates.
@@ -142,9 +155,50 @@ public class GoServerCodegen extends AbstractGoCodegen {
supportingFiles.add(new SupportingFile("Dockerfile.mustache", "", "Dockerfile"));
supportingFiles.add(new SupportingFile("routers.mustache", sourceFolder, "routers.go"));
supportingFiles.add(new SupportingFile("logger.mustache", sourceFolder, "logger.go"));
supportingFiles.add(new SupportingFile("api.mustache", sourceFolder, "api.go"));
writeOptional(outputFolder, new SupportingFile("README.mustache", "", "README.md"));
}
@Override
public Map<String, Object> postProcessOperationsWithModels(Map<String, Object> objs, List<Object> allModels) {
objs = super.postProcessOperationsWithModels(objs, allModels);
@SuppressWarnings("unchecked")
Map<String, Object> objectMap = (Map<String, Object>) objs.get("operations");
@SuppressWarnings("unchecked")
List<CodegenOperation> operations = (List<CodegenOperation>) objectMap.get("operation");
List<Map<String, String>> imports = (List<Map<String, String>>) objs.get("imports");
if (imports == null)
return objs;
// override imports to only include packages for interface parameters
imports.clear();
boolean addedOptionalImport = false;
boolean addedTimeImport = false;
boolean addedOSImport = false;
boolean addedReflectImport = false;
for (CodegenOperation operation : operations) {
for (CodegenParameter param : operation.allParams) {
// import "os" if the operation uses files
if (!addedOSImport && "*os.File".equals(param.dataType)) {
imports.add(createMapping("import", "os"));
addedOSImport = true;
}
// import "time" if the operation has a required time parameter.
if (param.required) {
if (!addedTimeImport && "time.Time".equals(param.dataType)) {
imports.add(createMapping("import", "time"));
addedTimeImport = true;
}
}
}
}
return objs;
}
@Override
public String apiPackage() {
return sourceFolder;

View File

@@ -0,0 +1,24 @@
{{>partial_header}}
package {{packageName}}
import (
"net/http"{{#apiInfo}}{{#apis}}{{#imports}}
"{{import}}"{{/imports}}{{/apis}}{{/apiInfo}}
)
{{#apiInfo}}{{#apis}}
// {{classname}}Router defines the required methods for binding the api requests to a responses for the {{classname}}
// The {{classname}}Router implementation should parse necessary information from the http request,
// pass the data to a {{classname}}Servicer to perform the required actions, then write the service results to the http response.
type {{classname}}Router interface { {{#operations}}{{#operation}}
{{operationId}}(http.ResponseWriter, *http.Request){{/operation}}{{/operations}}
}{{/apis}}{{/apiInfo}}{{#apiInfo}}{{#apis}}
// {{classname}}Servicer defines the api actions for the {{classname}} service
// This interface intended to stay up to date with the openapi yaml used to generate it,
// while the service implementation can ignored with the .openapi-generator-ignore file
// and updated with the logic required for the API.
type {{classname}}Servicer interface { {{#operations}}{{#operation}}
{{operationId}}({{#allParams}}{{dataType}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) (interface{}, error){{/operation}}{{/operations}}
}{{/apis}}{{/apiInfo}}

View File

@@ -1,13 +1,85 @@
{{>partial_header}}
package {{packageName}}
{{#operations}}
import (
"encoding/json"
"net/http"
){{#operation}}
"strings"
"github.com/gorilla/mux"
)
// A {{classname}}Controller binds http requests to an api service and writes the service results to the http response
type {{classname}}Controller struct {
service {{classname}}Servicer
}
// New{{classname}}Controller creates a default api controller
func New{{classname}}Controller(s {{classname}}Servicer) {{classname}}Router {
return &{{classname}}Controller{ service: s }
}
// Routes returns all of the api route for the {{classname}}Controller
func (c *{{classname}}Controller) Routes() Routes {
return Routes{ {{#operations}}{{#operation}}
{
"{{operationId}}",
strings.ToUpper("{{httpMethod}}"),
"{{{basePathWithoutHost}}}{{{path}}}",
c.{{operationId}},
},{{/operation}}{{/operations}}
}
}{{#operations}}{{#operation}}
// {{nickname}} - {{{summary}}}
func {{nickname}}(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
func (c *{{classname}}Controller) {{nickname}}(w http.ResponseWriter, r *http.Request) { {{#hasFormParams}}
err := r.ParseForm()
if err != nil {
w.WriteHeader(500)
return
}
{{/hasFormParams}}{{#hasPathParams}}
params := mux.Vars(r){{/hasPathParams}}{{#hasQueryParams}}
query := r.URL.Query(){{/hasQueryParams}}{{#allParams}}{{#isPathParam}}{{#isLong}}
{{paramName}}, err := parseIntParameter(params["{{paramName}}"])
if err != nil {
w.WriteHeader(500)
return
}
{{/isLong}}{{^isLong}}
{{paramName}} := params["{{paramName}}"]{{/isLong}}{{/isPathParam}}{{#isQueryParam}}{{#isLong}}
{{paramName}}, err := parseIntParameter(query.Get("{{paramName}}"))
if err != nil {
w.WriteHeader(500)
return
}
{{/isLong}}{{^isLong}}
{{paramName}} := {{#isListContainer}}strings.Split({{/isListContainer}}query.Get("{{paramName}}"){{#isListContainer}}, ","){{/isListContainer}}{{/isLong}}{{/isQueryParam}}{{#isFormParam}}{{#isFile}}
{{paramName}}, err := ReadFormFileToTempFile(r, "{{paramName}}")
if err != nil {
w.WriteHeader(500)
return
}
{{/isFile}}{{#isLong}}
{{paramName}}, err := parseIntParameter( r.FormValue("{{paramName}}"))
if err != nil {
w.WriteHeader(500)
return
}
{{/isLong}}{{^isFile}}{{^isLong}}
{{paramName}} := r.FormValue("{{paramName}}"){{/isLong}}{{/isFile}}{{/isFormParam}}{{#isHeaderParam}}
{{paramName}} := r.Header.Get("{{paramName}}"){{/isHeaderParam}}{{#isBodyParam}}
{{paramName}} := &{{dataType}}{}
if err := json.NewDecoder(r.Body).Decode(&{{paramName}}); err != nil {
w.WriteHeader(500)
return
}
{{/isBodyParam}}{{/allParams}}
result, err := c.service.{{nickname}}({{#allParams}}{{#isBodyParam}}*{{/isBodyParam}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}})
if err != nil {
w.WriteHeader(500)
return
}
EncodeJSONResponse(result, nil, w)
}{{/operation}}{{/operations}}

View File

@@ -12,13 +12,16 @@ import (
//
// sw "github.com/myname/myrepo/{{sourceFolder}}"
//
sw "./{{sourceFolder}}"
{{packageName}} "./{{sourceFolder}}"
)
func main() {
log.Printf("Server started")
router := sw.NewRouter()
{{#apiInfo}}{{#apis}}
{{classname}}Service := {{packageName}}.New{{classname}}Service()
{{classname}}Controller := {{packageName}}.New{{classname}}Controller({{classname}}Service)
{{/apis}}{{/apiInfo}}
router := {{packageName}}.NewRouter({{#apiInfo}}{{#apis}}{{classname}}Controller{{#hasMore}}, {{/hasMore}}{{/apis}}{{/apiInfo}})
log.Fatal(http.ListenAndServe(":{{serverPort}}", router))
}

View File

@@ -2,13 +2,16 @@
package {{packageName}}
import (
"fmt"
"encoding/json"
"io/ioutil"
"net/http"
"strings"
"os"
"strconv"
"github.com/gorilla/mux"
)
// A Route defines the parameters for an api endpoint
type Route struct {
Name string
Method string
@@ -16,11 +19,19 @@ type Route struct {
HandlerFunc http.HandlerFunc
}
// Routes are a collection of defined api endpoints
type Routes []Route
func NewRouter() *mux.Router {
// Router defines the required methods for retrieving api routes
type Router interface {
Routes() Routes
}
// NewRouter creates a new router for any number of api routers
func NewRouter(routers ...Router) *mux.Router {
router := mux.NewRouter().StrictSlash(true)
for _, route := range routes {
for _, api := range routers {
for _, route := range api.Routes() {
var handler http.Handler
handler = route.HandlerFunc
handler = Logger(handler, route.Name)
@@ -31,26 +42,48 @@ func NewRouter() *mux.Router {
Name(route.Name).
Handler(handler)
}
}
return router
}
func Index(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello World!")
// 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 {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
if status != nil {
w.WriteHeader(*status)
} else {
w.WriteHeader(http.StatusOK)
}
var routes = Routes{
{
"Index",
"GET",
"{{{basePathWithoutHost}}}/",
Index,
},{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}
{
"{{operationId}}",
strings.ToUpper("{{httpMethod}}"),
"{{{basePathWithoutHost}}}{{{path}}}",
{{operationId}},
},{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
return json.NewEncoder(w).Encode(i)
}
// ReadFormFileToTempFile reads file data from a request form and writes it to a temporary file
func ReadFormFileToTempFile(r *http.Request, key string) (*os.File, error) {
r.ParseForm()
formFile, _, err := r.FormFile(key)
if err != nil {
return nil, err
}
defer formFile.Close()
file, err := ioutil.TempFile("tmp", key)
if err != nil {
return nil, err
}
defer file.Close()
fileBytes, err := ioutil.ReadAll(formFile)
if err != nil {
return nil, err
}
file.Write(fileBytes)
return file, nil
}
// parseIntParameter parses a sting parameter to an int64
func parseIntParameter(param string) (int64, error) {
return strconv.ParseInt(param, 10, 64)
}

View File

@@ -0,0 +1,25 @@
{{>partial_header}}
package {{packageName}}
import (
"errors"{{#imports}}
"{{import}}"{{/imports}}
)
// {{classname}}Service is a service that implents the logic for the {{classname}}Servicer
// This service should implement the business logic for every endpoint for the {{classname}} API.
// Include any external packages or services that will be required by this service.
type {{classname}}Service struct {
}
// New{{classname}}Service creates a default api service
func New{{classname}}Service() {{classname}}Servicer {
return &{{classname}}Service{}
}{{#operations}}{{#operation}}
// {{nickname}} - {{summary}}
func (s *{{classname}}Service) {{nickname}}({{#allParams}}{{paramName}} {{dataType}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) (interface{}, error) {
// TODO - update {{nickname}} with the required logic for this service method.
// Add {{classFilename}}_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation.
return nil, errors.New("service method '{{nickname}}' not implemented")
}{{/operation}}{{/operations}}

View File

@@ -0,0 +1,96 @@
/*
* 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 (
"net/http"
"os"
)
// PetApiRouter defines the required methods for binding the api requests to a responses for the PetApi
// The PetApiRouter implementation should parse necessary information from the http request,
// pass the data to a PetApiServicer to perform the required actions, then write the service results to the http response.
type PetApiRouter interface {
AddPet(http.ResponseWriter, *http.Request)
DeletePet(http.ResponseWriter, *http.Request)
FindPetsByStatus(http.ResponseWriter, *http.Request)
FindPetsByTags(http.ResponseWriter, *http.Request)
GetPetById(http.ResponseWriter, *http.Request)
UpdatePet(http.ResponseWriter, *http.Request)
UpdatePetWithForm(http.ResponseWriter, *http.Request)
UploadFile(http.ResponseWriter, *http.Request)
}
// StoreApiRouter defines the required methods for binding the api requests to a responses for the StoreApi
// The StoreApiRouter implementation should parse necessary information from the http request,
// pass the data to a StoreApiServicer to perform the required actions, then write the service results to the http response.
type StoreApiRouter interface {
DeleteOrder(http.ResponseWriter, *http.Request)
GetInventory(http.ResponseWriter, *http.Request)
GetOrderById(http.ResponseWriter, *http.Request)
PlaceOrder(http.ResponseWriter, *http.Request)
}
// UserApiRouter defines the required methods for binding the api requests to a responses for the UserApi
// The UserApiRouter implementation should parse necessary information from the http request,
// pass the data to a UserApiServicer to perform the required actions, then write the service results to the http response.
type UserApiRouter interface {
CreateUser(http.ResponseWriter, *http.Request)
CreateUsersWithArrayInput(http.ResponseWriter, *http.Request)
CreateUsersWithListInput(http.ResponseWriter, *http.Request)
DeleteUser(http.ResponseWriter, *http.Request)
GetUserByName(http.ResponseWriter, *http.Request)
LoginUser(http.ResponseWriter, *http.Request)
LogoutUser(http.ResponseWriter, *http.Request)
UpdateUser(http.ResponseWriter, *http.Request)
}
// PetApiServicer defines the api actions for the PetApi service
// This interface intended to stay up to date with the openapi yaml used to generate it,
// while the service implementation can ignored with the .openapi-generator-ignore file
// and updated with the logic required for the API.
type PetApiServicer interface {
AddPet(Pet) (interface{}, error)
DeletePet(int64, string) (interface{}, error)
FindPetsByStatus([]string) (interface{}, error)
FindPetsByTags([]string) (interface{}, error)
GetPetById(int64) (interface{}, error)
UpdatePet(Pet) (interface{}, error)
UpdatePetWithForm(int64, string, string) (interface{}, error)
UploadFile(int64, string, *os.File) (interface{}, error)
}
// StoreApiServicer defines the api actions for the StoreApi service
// This interface intended to stay up to date with the openapi yaml used to generate it,
// while the service implementation can ignored with the .openapi-generator-ignore file
// and updated with the logic required for the API.
type StoreApiServicer interface {
DeleteOrder(string) (interface{}, error)
GetInventory() (interface{}, error)
GetOrderById(int64) (interface{}, error)
PlaceOrder(Order) (interface{}, error)
}
// UserApiServicer defines the api actions for the UserApi service
// This interface intended to stay up to date with the openapi yaml used to generate it,
// while the service implementation can ignored with the .openapi-generator-ignore file
// and updated with the logic required for the API.
type UserApiServicer interface {
CreateUser(User) (interface{}, error)
CreateUsersWithArrayInput([]User) (interface{}, error)
CreateUsersWithListInput([]User) (interface{}, error)
DeleteUser(string) (interface{}, error)
GetUserByName(string) (interface{}, error)
LoginUser(string, string) (interface{}, error)
LogoutUser() (interface{}, error)
UpdateUser(string, User) (interface{}, error)
}

View File

@@ -10,53 +10,227 @@
package petstoreserver
import (
"encoding/json"
"net/http"
"strings"
"github.com/gorilla/mux"
)
// A PetApiController binds http requests to an api service and writes the service results to the http response
type PetApiController struct {
service PetApiServicer
}
// NewPetApiController creates a default api controller
func NewPetApiController(s PetApiServicer) PetApiRouter {
return &PetApiController{ service: s }
}
// Routes returns all of the api route for the PetApiController
func (c *PetApiController) Routes() Routes {
return Routes{
{
"AddPet",
strings.ToUpper("Post"),
"/v2/pet",
c.AddPet,
},
{
"DeletePet",
strings.ToUpper("Delete"),
"/v2/pet/{petId}",
c.DeletePet,
},
{
"FindPetsByStatus",
strings.ToUpper("Get"),
"/v2/pet/findByStatus",
c.FindPetsByStatus,
},
{
"FindPetsByTags",
strings.ToUpper("Get"),
"/v2/pet/findByTags",
c.FindPetsByTags,
},
{
"GetPetById",
strings.ToUpper("Get"),
"/v2/pet/{petId}",
c.GetPetById,
},
{
"UpdatePet",
strings.ToUpper("Put"),
"/v2/pet",
c.UpdatePet,
},
{
"UpdatePetWithForm",
strings.ToUpper("Post"),
"/v2/pet/{petId}",
c.UpdatePetWithForm,
},
{
"UploadFile",
strings.ToUpper("Post"),
"/v2/pet/{petId}/uploadImage",
c.UploadFile,
},
}
}
// AddPet - Add a new pet to the store
func AddPet(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
func (c *PetApiController) AddPet(w http.ResponseWriter, r *http.Request) {
body := &Pet{}
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
w.WriteHeader(500)
return
}
result, err := c.service.AddPet(*body)
if err != nil {
w.WriteHeader(500)
return
}
EncodeJSONResponse(result, nil, w)
}
// DeletePet - Deletes a pet
func DeletePet(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
func (c *PetApiController) DeletePet(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
petId, err := parseIntParameter(params["petId"])
if err != nil {
w.WriteHeader(500)
return
}
apiKey := r.Header.Get("apiKey")
result, err := c.service.DeletePet(petId, apiKey)
if err != nil {
w.WriteHeader(500)
return
}
EncodeJSONResponse(result, nil, w)
}
// FindPetsByStatus - Finds Pets by status
func FindPetsByStatus(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
func (c *PetApiController) FindPetsByStatus(w http.ResponseWriter, r *http.Request) {
query := r.URL.Query()
status := strings.Split(query.Get("status"), ",")
result, err := c.service.FindPetsByStatus(status)
if err != nil {
w.WriteHeader(500)
return
}
EncodeJSONResponse(result, nil, w)
}
// FindPetsByTags - Finds Pets by tags
func FindPetsByTags(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
func (c *PetApiController) FindPetsByTags(w http.ResponseWriter, r *http.Request) {
query := r.URL.Query()
tags := strings.Split(query.Get("tags"), ",")
result, err := c.service.FindPetsByTags(tags)
if err != nil {
w.WriteHeader(500)
return
}
EncodeJSONResponse(result, nil, w)
}
// GetPetById - Find pet by ID
func GetPetById(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
func (c *PetApiController) GetPetById(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
petId, err := parseIntParameter(params["petId"])
if err != nil {
w.WriteHeader(500)
return
}
result, err := c.service.GetPetById(petId)
if err != nil {
w.WriteHeader(500)
return
}
EncodeJSONResponse(result, nil, w)
}
// UpdatePet - Update an existing pet
func UpdatePet(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
func (c *PetApiController) UpdatePet(w http.ResponseWriter, r *http.Request) {
body := &Pet{}
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
w.WriteHeader(500)
return
}
result, err := c.service.UpdatePet(*body)
if err != nil {
w.WriteHeader(500)
return
}
EncodeJSONResponse(result, nil, w)
}
// UpdatePetWithForm - Updates a pet in the store with form data
func UpdatePetWithForm(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
func (c *PetApiController) UpdatePetWithForm(w http.ResponseWriter, r *http.Request) {
err := r.ParseForm()
if err != nil {
w.WriteHeader(500)
return
}
params := mux.Vars(r)
petId, err := parseIntParameter(params["petId"])
if err != nil {
w.WriteHeader(500)
return
}
name := r.FormValue("name")
status := r.FormValue("status")
result, err := c.service.UpdatePetWithForm(petId, name, status)
if err != nil {
w.WriteHeader(500)
return
}
EncodeJSONResponse(result, nil, w)
}
// UploadFile - uploads an image
func UploadFile(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
func (c *PetApiController) UploadFile(w http.ResponseWriter, r *http.Request) {
err := r.ParseForm()
if err != nil {
w.WriteHeader(500)
return
}
params := mux.Vars(r)
petId, err := parseIntParameter(params["petId"])
if err != nil {
w.WriteHeader(500)
return
}
additionalMetadata := r.FormValue("additionalMetadata")
file, err := ReadFormFileToTempFile(r, "file")
if err != nil {
w.WriteHeader(500)
return
}
result, err := c.service.UploadFile(petId, additionalMetadata, file)
if err != nil {
w.WriteHeader(500)
return
}
EncodeJSONResponse(result, nil, w)
}

View File

@@ -0,0 +1,82 @@
/*
* 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 (
"errors"
"os"
)
// PetApiService is a service that implents the logic for the PetApiServicer
// This service should implement the business logic for every endpoint for the PetApi API.
// Include any external packages or services that will be required by this service.
type PetApiService struct {
}
// NewPetApiService creates a default api service
func NewPetApiService() PetApiServicer {
return &PetApiService{}
}
// AddPet - Add a new pet to the store
func (s *PetApiService) AddPet(body Pet) (interface{}, error) {
// TODO - update AddPet 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.
return nil, errors.New("service method 'AddPet' not implemented")
}
// DeletePet - Deletes a pet
func (s *PetApiService) DeletePet(petId int64, apiKey string) (interface{}, error) {
// TODO - update DeletePet 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.
return nil, errors.New("service method 'DeletePet' not implemented")
}
// FindPetsByStatus - Finds Pets by status
func (s *PetApiService) FindPetsByStatus(status []string) (interface{}, error) {
// TODO - update FindPetsByStatus 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.
return nil, errors.New("service method 'FindPetsByStatus' not implemented")
}
// FindPetsByTags - Finds Pets by tags
func (s *PetApiService) FindPetsByTags(tags []string) (interface{}, error) {
// TODO - update FindPetsByTags 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.
return nil, errors.New("service method 'FindPetsByTags' not implemented")
}
// GetPetById - Find pet by ID
func (s *PetApiService) GetPetById(petId int64) (interface{}, error) {
// TODO - update GetPetById 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.
return nil, errors.New("service method 'GetPetById' not implemented")
}
// UpdatePet - Update an existing pet
func (s *PetApiService) UpdatePet(body Pet) (interface{}, error) {
// TODO - update UpdatePet 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.
return nil, errors.New("service method 'UpdatePet' not implemented")
}
// UpdatePetWithForm - Updates a pet in the store with form data
func (s *PetApiService) UpdatePetWithForm(petId int64, name string, status string) (interface{}, error) {
// TODO - update UpdatePetWithForm 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.
return nil, errors.New("service method 'UpdatePetWithForm' not implemented")
}
// UploadFile - uploads an image
func (s *PetApiService) UploadFile(petId int64, additionalMetadata string, file *os.File) (interface{}, error) {
// TODO - update UploadFile 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.
return nil, errors.New("service method 'UploadFile' not implemented")
}

View File

@@ -10,29 +10,108 @@
package petstoreserver
import (
"encoding/json"
"net/http"
"strings"
"github.com/gorilla/mux"
)
// A StoreApiController binds http requests to an api service and writes the service results to the http response
type StoreApiController struct {
service StoreApiServicer
}
// NewStoreApiController creates a default api controller
func NewStoreApiController(s StoreApiServicer) StoreApiRouter {
return &StoreApiController{ service: s }
}
// Routes returns all of the api route for the StoreApiController
func (c *StoreApiController) Routes() Routes {
return Routes{
{
"DeleteOrder",
strings.ToUpper("Delete"),
"/v2/store/order/{orderId}",
c.DeleteOrder,
},
{
"GetInventory",
strings.ToUpper("Get"),
"/v2/store/inventory",
c.GetInventory,
},
{
"GetOrderById",
strings.ToUpper("Get"),
"/v2/store/order/{orderId}",
c.GetOrderById,
},
{
"PlaceOrder",
strings.ToUpper("Post"),
"/v2/store/order",
c.PlaceOrder,
},
}
}
// DeleteOrder - Delete purchase order by ID
func DeleteOrder(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
func (c *StoreApiController) DeleteOrder(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
orderId := params["orderId"]
result, err := c.service.DeleteOrder(orderId)
if err != nil {
w.WriteHeader(500)
return
}
EncodeJSONResponse(result, nil, w)
}
// GetInventory - Returns pet inventories by status
func GetInventory(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
func (c *StoreApiController) GetInventory(w http.ResponseWriter, r *http.Request) {
result, err := c.service.GetInventory()
if err != nil {
w.WriteHeader(500)
return
}
EncodeJSONResponse(result, nil, w)
}
// GetOrderById - Find purchase order by ID
func GetOrderById(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
func (c *StoreApiController) GetOrderById(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
orderId, err := parseIntParameter(params["orderId"])
if err != nil {
w.WriteHeader(500)
return
}
result, err := c.service.GetOrderById(orderId)
if err != nil {
w.WriteHeader(500)
return
}
EncodeJSONResponse(result, nil, w)
}
// PlaceOrder - Place an order for a pet
func PlaceOrder(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
func (c *StoreApiController) PlaceOrder(w http.ResponseWriter, r *http.Request) {
body := &Order{}
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
w.WriteHeader(500)
return
}
result, err := c.service.PlaceOrder(*body)
if err != nil {
w.WriteHeader(500)
return
}
EncodeJSONResponse(result, nil, w)
}

View File

@@ -0,0 +1,53 @@
/*
* 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 (
"errors"
)
// StoreApiService is a service that implents the logic for the StoreApiServicer
// This service should implement the business logic for every endpoint for the StoreApi API.
// Include any external packages or services that will be required by this service.
type StoreApiService struct {
}
// NewStoreApiService creates a default api service
func NewStoreApiService() StoreApiServicer {
return &StoreApiService{}
}
// DeleteOrder - Delete purchase order by ID
func (s *StoreApiService) DeleteOrder(orderId string) (interface{}, error) {
// TODO - update DeleteOrder with the required logic for this service method.
// Add api_store_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation.
return nil, errors.New("service method 'DeleteOrder' not implemented")
}
// GetInventory - Returns pet inventories by status
func (s *StoreApiService) GetInventory() (interface{}, error) {
// TODO - update GetInventory with the required logic for this service method.
// Add api_store_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation.
return nil, errors.New("service method 'GetInventory' not implemented")
}
// GetOrderById - Find purchase order by ID
func (s *StoreApiService) GetOrderById(orderId int64) (interface{}, error) {
// TODO - update GetOrderById with the required logic for this service method.
// Add api_store_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation.
return nil, errors.New("service method 'GetOrderById' not implemented")
}
// PlaceOrder - Place an order for a pet
func (s *StoreApiService) PlaceOrder(body Order) (interface{}, error) {
// TODO - update PlaceOrder with the required logic for this service method.
// Add api_store_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation.
return nil, errors.New("service method 'PlaceOrder' not implemented")
}

View File

@@ -10,53 +10,194 @@
package petstoreserver
import (
"encoding/json"
"net/http"
"strings"
"github.com/gorilla/mux"
)
// A UserApiController binds http requests to an api service and writes the service results to the http response
type UserApiController struct {
service UserApiServicer
}
// NewUserApiController creates a default api controller
func NewUserApiController(s UserApiServicer) UserApiRouter {
return &UserApiController{ service: s }
}
// Routes returns all of the api route for the UserApiController
func (c *UserApiController) Routes() Routes {
return Routes{
{
"CreateUser",
strings.ToUpper("Post"),
"/v2/user",
c.CreateUser,
},
{
"CreateUsersWithArrayInput",
strings.ToUpper("Post"),
"/v2/user/createWithArray",
c.CreateUsersWithArrayInput,
},
{
"CreateUsersWithListInput",
strings.ToUpper("Post"),
"/v2/user/createWithList",
c.CreateUsersWithListInput,
},
{
"DeleteUser",
strings.ToUpper("Delete"),
"/v2/user/{username}",
c.DeleteUser,
},
{
"GetUserByName",
strings.ToUpper("Get"),
"/v2/user/{username}",
c.GetUserByName,
},
{
"LoginUser",
strings.ToUpper("Get"),
"/v2/user/login",
c.LoginUser,
},
{
"LogoutUser",
strings.ToUpper("Get"),
"/v2/user/logout",
c.LogoutUser,
},
{
"UpdateUser",
strings.ToUpper("Put"),
"/v2/user/{username}",
c.UpdateUser,
},
}
}
// CreateUser - Create user
func CreateUser(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
func (c *UserApiController) CreateUser(w http.ResponseWriter, r *http.Request) {
body := &User{}
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
w.WriteHeader(500)
return
}
result, err := c.service.CreateUser(*body)
if err != nil {
w.WriteHeader(500)
return
}
EncodeJSONResponse(result, nil, w)
}
// CreateUsersWithArrayInput - Creates list of users with given input array
func CreateUsersWithArrayInput(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
func (c *UserApiController) CreateUsersWithArrayInput(w http.ResponseWriter, r *http.Request) {
body := &[]User{}
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
w.WriteHeader(500)
return
}
result, err := c.service.CreateUsersWithArrayInput(*body)
if err != nil {
w.WriteHeader(500)
return
}
EncodeJSONResponse(result, nil, w)
}
// CreateUsersWithListInput - Creates list of users with given input array
func CreateUsersWithListInput(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
func (c *UserApiController) CreateUsersWithListInput(w http.ResponseWriter, r *http.Request) {
body := &[]User{}
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
w.WriteHeader(500)
return
}
result, err := c.service.CreateUsersWithListInput(*body)
if err != nil {
w.WriteHeader(500)
return
}
EncodeJSONResponse(result, nil, w)
}
// DeleteUser - Delete user
func DeleteUser(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
func (c *UserApiController) DeleteUser(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
username := params["username"]
result, err := c.service.DeleteUser(username)
if err != nil {
w.WriteHeader(500)
return
}
EncodeJSONResponse(result, nil, w)
}
// GetUserByName - Get user by user name
func GetUserByName(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
func (c *UserApiController) GetUserByName(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
username := params["username"]
result, err := c.service.GetUserByName(username)
if err != nil {
w.WriteHeader(500)
return
}
EncodeJSONResponse(result, nil, w)
}
// LoginUser - Logs user into the system
func LoginUser(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
func (c *UserApiController) LoginUser(w http.ResponseWriter, r *http.Request) {
query := r.URL.Query()
username := query.Get("username")
password := query.Get("password")
result, err := c.service.LoginUser(username, password)
if err != nil {
w.WriteHeader(500)
return
}
EncodeJSONResponse(result, nil, w)
}
// LogoutUser - Logs out current logged in user session
func LogoutUser(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
func (c *UserApiController) LogoutUser(w http.ResponseWriter, r *http.Request) {
result, err := c.service.LogoutUser()
if err != nil {
w.WriteHeader(500)
return
}
EncodeJSONResponse(result, nil, w)
}
// UpdateUser - Updated user
func UpdateUser(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
func (c *UserApiController) UpdateUser(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
username := params["username"]
body := &User{}
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
w.WriteHeader(500)
return
}
result, err := c.service.UpdateUser(username, *body)
if err != nil {
w.WriteHeader(500)
return
}
EncodeJSONResponse(result, nil, w)
}

View File

@@ -0,0 +1,81 @@
/*
* 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 (
"errors"
)
// UserApiService is a service that implents the logic for the UserApiServicer
// This service should implement the business logic for every endpoint for the UserApi API.
// Include any external packages or services that will be required by this service.
type UserApiService struct {
}
// NewUserApiService creates a default api service
func NewUserApiService() UserApiServicer {
return &UserApiService{}
}
// CreateUser - Create user
func (s *UserApiService) CreateUser(body User) (interface{}, error) {
// TODO - update CreateUser with the required logic for this service method.
// Add api_user_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation.
return nil, errors.New("service method 'CreateUser' not implemented")
}
// CreateUsersWithArrayInput - Creates list of users with given input array
func (s *UserApiService) CreateUsersWithArrayInput(body []User) (interface{}, error) {
// TODO - update CreateUsersWithArrayInput with the required logic for this service method.
// Add api_user_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation.
return nil, errors.New("service method 'CreateUsersWithArrayInput' not implemented")
}
// CreateUsersWithListInput - Creates list of users with given input array
func (s *UserApiService) CreateUsersWithListInput(body []User) (interface{}, error) {
// TODO - update CreateUsersWithListInput with the required logic for this service method.
// Add api_user_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation.
return nil, errors.New("service method 'CreateUsersWithListInput' not implemented")
}
// DeleteUser - Delete user
func (s *UserApiService) DeleteUser(username string) (interface{}, error) {
// TODO - update DeleteUser with the required logic for this service method.
// Add api_user_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation.
return nil, errors.New("service method 'DeleteUser' not implemented")
}
// GetUserByName - Get user by user name
func (s *UserApiService) GetUserByName(username string) (interface{}, error) {
// TODO - update GetUserByName with the required logic for this service method.
// Add api_user_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation.
return nil, errors.New("service method 'GetUserByName' not implemented")
}
// LoginUser - Logs user into the system
func (s *UserApiService) LoginUser(username string, password string) (interface{}, error) {
// TODO - update LoginUser with the required logic for this service method.
// Add api_user_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation.
return nil, errors.New("service method 'LoginUser' not implemented")
}
// LogoutUser - Logs out current logged in user session
func (s *UserApiService) LogoutUser() (interface{}, error) {
// TODO - update LogoutUser with the required logic for this service method.
// Add api_user_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation.
return nil, errors.New("service method 'LogoutUser' not implemented")
}
// UpdateUser - Updated user
func (s *UserApiService) UpdateUser(username string, body User) (interface{}, error) {
// TODO - update UpdateUser with the required logic for this service method.
// Add api_user_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation.
return nil, errors.New("service method 'UpdateUser' not implemented")
}

View File

@@ -10,13 +10,16 @@
package petstoreserver
import (
"fmt"
"encoding/json"
"io/ioutil"
"net/http"
"strings"
"os"
"strconv"
"github.com/gorilla/mux"
)
// A Route defines the parameters for an api endpoint
type Route struct {
Name string
Method string
@@ -24,11 +27,19 @@ type Route struct {
HandlerFunc http.HandlerFunc
}
// Routes are a collection of defined api endpoints
type Routes []Route
func NewRouter() *mux.Router {
// Router defines the required methods for retrieving api routes
type Router interface {
Routes() Routes
}
// NewRouter creates a new router for any number of api routers
func NewRouter(routers ...Router) *mux.Router {
router := mux.NewRouter().StrictSlash(true)
for _, route := range routes {
for _, api := range routers {
for _, route := range api.Routes() {
var handler http.Handler
handler = route.HandlerFunc
handler = Logger(handler, route.Name)
@@ -39,159 +50,48 @@ func NewRouter() *mux.Router {
Name(route.Name).
Handler(handler)
}
}
return router
}
func Index(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello World!")
// 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 {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
if status != nil {
w.WriteHeader(*status)
} else {
w.WriteHeader(http.StatusOK)
}
var routes = Routes{
{
"Index",
"GET",
"/v2/",
Index,
},
{
"AddPet",
strings.ToUpper("Post"),
"/v2/pet",
AddPet,
},
{
"DeletePet",
strings.ToUpper("Delete"),
"/v2/pet/{petId}",
DeletePet,
},
{
"FindPetsByStatus",
strings.ToUpper("Get"),
"/v2/pet/findByStatus",
FindPetsByStatus,
},
{
"FindPetsByTags",
strings.ToUpper("Get"),
"/v2/pet/findByTags",
FindPetsByTags,
},
{
"GetPetById",
strings.ToUpper("Get"),
"/v2/pet/{petId}",
GetPetById,
},
{
"UpdatePet",
strings.ToUpper("Put"),
"/v2/pet",
UpdatePet,
},
{
"UpdatePetWithForm",
strings.ToUpper("Post"),
"/v2/pet/{petId}",
UpdatePetWithForm,
},
{
"UploadFile",
strings.ToUpper("Post"),
"/v2/pet/{petId}/uploadImage",
UploadFile,
},
{
"DeleteOrder",
strings.ToUpper("Delete"),
"/v2/store/order/{orderId}",
DeleteOrder,
},
{
"GetInventory",
strings.ToUpper("Get"),
"/v2/store/inventory",
GetInventory,
},
{
"GetOrderById",
strings.ToUpper("Get"),
"/v2/store/order/{orderId}",
GetOrderById,
},
{
"PlaceOrder",
strings.ToUpper("Post"),
"/v2/store/order",
PlaceOrder,
},
{
"CreateUser",
strings.ToUpper("Post"),
"/v2/user",
CreateUser,
},
{
"CreateUsersWithArrayInput",
strings.ToUpper("Post"),
"/v2/user/createWithArray",
CreateUsersWithArrayInput,
},
{
"CreateUsersWithListInput",
strings.ToUpper("Post"),
"/v2/user/createWithList",
CreateUsersWithListInput,
},
{
"DeleteUser",
strings.ToUpper("Delete"),
"/v2/user/{username}",
DeleteUser,
},
{
"GetUserByName",
strings.ToUpper("Get"),
"/v2/user/{username}",
GetUserByName,
},
{
"LoginUser",
strings.ToUpper("Get"),
"/v2/user/login",
LoginUser,
},
{
"LogoutUser",
strings.ToUpper("Get"),
"/v2/user/logout",
LogoutUser,
},
{
"UpdateUser",
strings.ToUpper("Put"),
"/v2/user/{username}",
UpdateUser,
},
return json.NewEncoder(w).Encode(i)
}
// ReadFormFileToTempFile reads file data from a request form and writes it to a temporary file
func ReadFormFileToTempFile(r *http.Request, key string) (*os.File, error) {
r.ParseForm()
formFile, _, err := r.FormFile(key)
if err != nil {
return nil, err
}
defer formFile.Close()
file, err := ioutil.TempFile("tmp", key)
if err != nil {
return nil, err
}
defer file.Close()
fileBytes, err := ioutil.ReadAll(formFile)
if err != nil {
return nil, err
}
file.Write(fileBytes)
return file, nil
}
// parseIntParameter parses a sting parameter to an int64
func parseIntParameter(param string) (int64, error) {
return strconv.ParseInt(param, 10, 64)
}

View File

@@ -20,13 +20,22 @@ import (
//
// sw "github.com/myname/myrepo/go"
//
sw "./go"
petstoreserver "./go"
)
func main() {
log.Printf("Server started")
router := sw.NewRouter()
PetApiService := petstoreserver.NewPetApiService()
PetApiController := petstoreserver.NewPetApiController(PetApiService)
StoreApiService := petstoreserver.NewStoreApiService()
StoreApiController := petstoreserver.NewStoreApiController(StoreApiService)
UserApiService := petstoreserver.NewUserApiService()
UserApiController := petstoreserver.NewUserApiController(UserApiService)
router := petstoreserver.NewRouter(PetApiController, StoreApiController, UserApiController)
log.Fatal(http.ListenAndServe(":8080", router))
}