Skip to content

Commit

Permalink
Add supporting response_body field in the google.api.HttpRule (gr…
Browse files Browse the repository at this point in the history
…pc-ecosystem#712)

Also:
* add flag `allow_repeated_fields_in_body` in `protoc-gen-grpc-gateway`
* add flag `json_names_for_fields` in `protoc-gen-swagger`
  • Loading branch information
doroginin committed Aug 12, 2018
1 parent bb916ca commit 936b4c8
Show file tree
Hide file tree
Showing 40 changed files with 1,329 additions and 61 deletions.
2 changes: 1 addition & 1 deletion Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Gopkg.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ required = [
[[constraint]]
# Also defined in bazelbuild/rules_go
# https://github.com/bazelbuild/rules_go/blob/436452edc29a2f1e0edc22d180fbb57c27e6d0af/go/private/repositories.bzl#L131
revision = "86e600f69ee4704c6efbf6a2a40a5c10700e76c2"
revision = "383e8b2c3b9e36c4076b235b32537292176bae20"
name = "google.golang.org/genproto"

[[constraint]]
Expand Down
23 changes: 20 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,17 @@ endif
SWAGGER_EXAMPLES=examples/proto/examplepb/echo_service.proto \
examples/proto/examplepb/a_bit_of_everything.proto \
examples/proto/examplepb/wrappers.proto \
examples/proto/examplepb/unannotated_echo_service.proto
examples/proto/examplepb/unannotated_echo_service.proto \
examples/proto/examplepb/response_body_service.proto

EXAMPLES=examples/proto/examplepb/echo_service.proto \
examples/proto/examplepb/a_bit_of_everything.proto \
examples/proto/examplepb/stream.proto \
examples/proto/examplepb/flow_combination.proto \
examples/proto/examplepb/wrappers.proto \
examples/proto/examplepb/unannotated_echo_service.proto
examples/proto/examplepb/unannotated_echo_service.proto \
examples/proto/examplepb/response_body_service.proto

EXAMPLE_SVCSRCS=$(EXAMPLES:.proto=.pb.go)
EXAMPLE_GWSRCS=$(EXAMPLES:.proto=.pb.gw.go)
EXAMPLE_SWAGGERSRCS=$(SWAGGER_EXAMPLES:.proto=.swagger.json)
Expand Down Expand Up @@ -105,7 +109,14 @@ UNANNOTATED_ECHO_EXAMPLE_SRCS=$(EXAMPLE_CLIENT_DIR)/unannotatedecho/api_client.g
$(EXAMPLE_CLIENT_DIR)/unannotatedecho/configuration.go \
$(EXAMPLE_CLIENT_DIR)/unannotatedecho/examplepb_unannotated_simple_message.go \
$(EXAMPLE_CLIENT_DIR)/unannotatedecho/unannotated_echo_service_api.go
EXAMPLE_CLIENT_SRCS=$(ECHO_EXAMPLE_SRCS) $(ABE_EXAMPLE_SRCS) $(UNANNOTATED_ECHO_EXAMPLE_SRCS)
RESPONSE_BODY_EXAMPLE_SPEC=examples/proto/examplepb/response_body_service.swagger.json
RESPONSE_BODY_EXAMPLE_SRCS=$(EXAMPLE_CLIENT_DIR)/responsebody/api_client.go \
$(EXAMPLE_CLIENT_DIR)/responsebody/api_response.go \
$(EXAMPLE_CLIENT_DIR)/responsebody/configuration.go \
$(EXAMPLE_CLIENT_DIR)/responsebody/examplepb_response_body.go \
$(EXAMPLE_CLIENT_DIR)/responsebody/response_body_service_api.go

EXAMPLE_CLIENT_SRCS=$(ECHO_EXAMPLE_SRCS) $(ABE_EXAMPLE_SRCS) $(UNANNOTATED_ECHO_EXAMPLE_SRCS) $(RESPONSE_BODY_EXAMPLE_SRCS)
SWAGGER_CODEGEN=swagger-codegen

PROTOC_INC_PATH=$(dir $(shell which protoc))/../include
Expand Down Expand Up @@ -164,6 +175,12 @@ $(UNANNOTATED_ECHO_EXAMPLE_SRCS): $(UNANNOTATED_ECHO_EXAMPLE_SPEC)
@rm -f $(EXAMPLE_CLIENT_DIR)/unannotatedecho/README.md \
$(EXAMPLE_CLIENT_DIR)/unannotatedecho/git_push.sh \
$(EXAMPLE_CLIENT_DIR)/unannotatedecho/.travis.yml
$(RESPONSE_BODY_EXAMPLE_SRCS): $(RESPONSE_BODY_EXAMPLE_SPEC)
$(SWAGGER_CODEGEN) generate -i $(RESPONSE_BODY_EXAMPLE_SPEC) \
-l go -o examples/clients/responsebody --additional-properties packageName=responsebody
@rm -f $(EXAMPLE_CLIENT_DIR)/responsebody/README.md \
$(EXAMPLE_CLIENT_DIR)/responsebody/git_push.sh \
$(EXAMPLE_CLIENT_DIR)/responsebody/.travis.yml

examples: $(EXAMPLE_SVCSRCS) $(EXAMPLE_GWSRCS) $(EXAMPLE_DEPSRCS) $(EXAMPLE_SWAGGERSRCS) $(EXAMPLE_CLIENT_SRCS)
test: examples
Expand Down
24 changes: 24 additions & 0 deletions examples/clients/responsebody/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so

# Folders
_obj
_test

# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out

*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*

_testmain.go

*.exe
*.test
*.prof
23 changes: 23 additions & 0 deletions examples/clients/responsebody/.swagger-codegen-ignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Swagger Codegen Ignore
# Generated by swagger-codegen https://github.com/swagger-api/swagger-codegen

# Use this file to prevent files from being overwritten by the generator.
# The patterns follow closely to .gitignore or .dockerignore.

# As an example, the C# client generator defines ApiClient.cs.
# You can make changes and tell Swagger Codgen to ignore just this file by uncommenting the following line:
#ApiClient.cs

# You can match any string of characters against a directory, file or extension with a single asterisk (*):
#foo/*/qux
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux

# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
#foo/**/qux
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux

# You can also negate patterns with an exclamation (!).
# For example, you can ignore all files in a docs folder with the file extension .md:
#docs/*.md
# Then explicitly reverse the ignore rule for a single file:
#!docs/README.md
164 changes: 164 additions & 0 deletions examples/clients/responsebody/api_client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
/*
* examples/proto/examplepb/response_body_service.proto
*
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
*
* OpenAPI spec version: version not set
*
* Generated by: https://github.com/swagger-api/swagger-codegen.git
*/

package responsebody

import (
"bytes"
"fmt"
"path/filepath"
"reflect"
"strings"
"net/url"
"io/ioutil"
"github.com/go-resty/resty"
)

type APIClient struct {
config *Configuration
}

func (c *APIClient) SelectHeaderContentType(contentTypes []string) string {

if len(contentTypes) == 0 {
return ""
}
if contains(contentTypes, "application/json") {
return "application/json"
}
return contentTypes[0] // use the first content type specified in 'consumes'
}

func (c *APIClient) SelectHeaderAccept(accepts []string) string {

if len(accepts) == 0 {
return ""
}
if contains(accepts, "application/json") {
return "application/json"
}
return strings.Join(accepts, ",")
}

func contains(haystack []string, needle string) bool {
for _, a := range haystack {
if strings.ToLower(a) == strings.ToLower(needle) {
return true
}
}
return false
}

func (c *APIClient) CallAPI(path string, method string,
postBody interface{},
headerParams map[string]string,
queryParams url.Values,
formParams map[string]string,
fileName string,
fileBytes []byte) (*resty.Response, error) {

rClient := c.prepareClient()
request := c.prepareRequest(rClient, postBody, headerParams, queryParams, formParams, fileName, fileBytes)

switch strings.ToUpper(method) {
case "GET":
response, err := request.Get(path)
return response, err
case "POST":
response, err := request.Post(path)
return response, err
case "PUT":
response, err := request.Put(path)
return response, err
case "PATCH":
response, err := request.Patch(path)
return response, err
case "DELETE":
response, err := request.Delete(path)
return response, err
}

return nil, fmt.Errorf("invalid method %v", method)
}

func (c *APIClient) ParameterToString(obj interface{}, collectionFormat string) string {
delimiter := ""
switch collectionFormat {
case "pipes":
delimiter = "|"
case "ssv":
delimiter = " "
case "tsv":
delimiter = "\t"
case "csv":
delimiter = ","
}

if reflect.TypeOf(obj).Kind() == reflect.Slice {
return strings.Trim(strings.Replace(fmt.Sprint(obj), " ", delimiter, -1), "[]")
}

return fmt.Sprintf("%v", obj)
}

func (c *APIClient) prepareClient() *resty.Client {

rClient := resty.New()

rClient.SetDebug(c.config.Debug)
if c.config.Transport != nil {
rClient.SetTransport(c.config.Transport)
}

if c.config.Timeout != nil {
rClient.SetTimeout(*c.config.Timeout)
}
rClient.SetLogger(ioutil.Discard)
return rClient
}

func (c *APIClient) prepareRequest(
rClient *resty.Client,
postBody interface{},
headerParams map[string]string,
queryParams url.Values,
formParams map[string]string,
fileName string,
fileBytes []byte) *resty.Request {


request := rClient.R()
request.SetBody(postBody)

if c.config.UserAgent != "" {
request.SetHeader("User-Agent", c.config.UserAgent)
}

// add header parameter, if any
if len(headerParams) > 0 {
request.SetHeaders(headerParams)
}

// add query parameter, if any
if len(queryParams) > 0 {
request.SetMultiValueQueryParams(queryParams)
}

// add form parameter, if any
if len(formParams) > 0 {
request.SetFormData(formParams)
}

if len(fileBytes) > 0 && fileName != "" {
_, fileNm := filepath.Split(fileName)
request.SetFileReader("file", fileNm, bytes.NewReader(fileBytes))
}
return request
}
44 changes: 44 additions & 0 deletions examples/clients/responsebody/api_response.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* examples/proto/examplepb/response_body_service.proto
*
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
*
* OpenAPI spec version: version not set
*
* Generated by: https://github.com/swagger-api/swagger-codegen.git
*/

package responsebody

import (
"net/http"
)

type APIResponse struct {
*http.Response `json:"-"`
Message string `json:"message,omitempty"`
// Operation is the name of the swagger operation.
Operation string `json:"operation,omitempty"`
// RequestURL is the request URL. This value is always available, even if the
// embedded *http.Response is nil.
RequestURL string `json:"url,omitempty"`
// Method is the HTTP method used for the request. This value is always
// available, even if the embedded *http.Response is nil.
Method string `json:"method,omitempty"`
// Payload holds the contents of the response body (which may be nil or empty).
// This is provided here as the raw response.Body() reader will have already
// been drained.
Payload []byte `json:"-"`
}

func NewAPIResponse(r *http.Response) *APIResponse {

response := &APIResponse{Response: r}
return response
}

func NewAPIResponseWithError(errorMessage string) *APIResponse {

response := &APIResponse{Message: errorMessage}
return response
}
67 changes: 67 additions & 0 deletions examples/clients/responsebody/configuration.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* examples/proto/examplepb/response_body_service.proto
*
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
*
* OpenAPI spec version: version not set
*
* Generated by: https://github.com/swagger-api/swagger-codegen.git
*/

package responsebody

import (
"encoding/base64"
"net/http"
"time"
)


type Configuration struct {
Username string `json:"userName,omitempty"`
Password string `json:"password,omitempty"`
APIKeyPrefix map[string]string `json:"APIKeyPrefix,omitempty"`
APIKey map[string]string `json:"APIKey,omitempty"`
Debug bool `json:"debug,omitempty"`
DebugFile string `json:"debugFile,omitempty"`
OAuthToken string `json:"oAuthToken,omitempty"`
BasePath string `json:"basePath,omitempty"`
Host string `json:"host,omitempty"`
Scheme string `json:"scheme,omitempty"`
AccessToken string `json:"accessToken,omitempty"`
DefaultHeader map[string]string `json:"defaultHeader,omitempty"`
UserAgent string `json:"userAgent,omitempty"`
APIClient *APIClient
Transport *http.Transport
Timeout *time.Duration `json:"timeout,omitempty"`
}

func NewConfiguration() *Configuration {
cfg := &Configuration{
BasePath: "http://localhost",
DefaultHeader: make(map[string]string),
APIKey: make(map[string]string),
APIKeyPrefix: make(map[string]string),
UserAgent: "Swagger-Codegen/1.0.0/go",
APIClient: &APIClient{},
}

cfg.APIClient.config = cfg
return cfg
}

func (c *Configuration) GetBasicAuthEncodedString() string {
return base64.StdEncoding.EncodeToString([]byte(c.Username + ":" + c.Password))
}

func (c *Configuration) AddDefaultHeader(key string, value string) {
c.DefaultHeader[key] = value
}

func (c *Configuration) GetAPIKeyWithPrefix(APIKeyIdentifier string) string {
if c.APIKeyPrefix[APIKeyIdentifier] != "" {
return c.APIKeyPrefix[APIKeyIdentifier] + " " + c.APIKey[APIKeyIdentifier]
}

return c.APIKey[APIKeyIdentifier]
}
Loading

0 comments on commit 936b4c8

Please sign in to comment.