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 14, 2018
1 parent bb916ca commit 72ba49e
Show file tree
Hide file tree
Showing 43 changed files with 1,351 additions and 76 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.

11 changes: 5 additions & 6 deletions Gopkg.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ required = [
revision = "6724a57986aff9bff1a1770e9347036def7c89f6"
name = "github.com/rogpeppe/fastuuid"

[[constraint]]
# Also defined in WORKSPACE
revision = "383e8b2c3b9e36c4076b235b32537292176bae20"
name = "google.golang.org/genproto"

[[override]]
# Also defined in WORKSPACE
revision = "eb3733d160e74a9c7e442f435eb3bea458e1d19f"
Expand All @@ -48,12 +53,6 @@ required = [
revision = "d11072e7ca9811b1100b80ca0269ac831f06d024"
name = "google.golang.org/grpc"

[[constraint]]
# Also defined in bazelbuild/rules_go
# https://github.com/bazelbuild/rules_go/blob/436452edc29a2f1e0edc22d180fbb57c27e6d0af/go/private/repositories.bzl#L131
revision = "86e600f69ee4704c6efbf6a2a40a5c10700e76c2"
name = "google.golang.org/genproto"

[[constraint]]
# Also defined in bazelbuild/rules_go
# https://github.com/bazelbuild/rules_go/blob/436452edc29a2f1e0edc22d180fbb57c27e6d0af/go/private/repositories.bzl#L138
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
25 changes: 15 additions & 10 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,16 @@ http_archive(
sha256 = "d03625db67e9fb0905bbd206fa97e32ae9da894fe234a493e7517fd25faec914",
)

load("@io_bazel_rules_go//go:def.bzl", "go_repository")
load("//:repositories.bzl", "repositories")
load("@io_bazel_rules_go//go:def.bzl", "go_rules_dependencies", "go_register_toolchains")

go_rules_dependencies()

go_register_toolchains()

load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies")

gazelle_dependencies()

load("@io_bazel_rules_go//go:def.bzl", "go_repository")
go_repository(
name = "org_golang_google_genproto",
commit = "383e8b2c3b9e36c4076b235b32537292176bae20",
importpath = "google.golang.org/genproto",
)

go_repository(
name = "com_github_rogpeppe_fastuuid",
Expand All @@ -48,6 +47,12 @@ go_repository(
importpath = "gopkg.in/yaml.v2",
)

load("//:repositories.bzl", "repositories")

repositories()

go_rules_dependencies()

go_register_toolchains()

load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies")

gazelle_dependencies()
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
}
Loading

0 comments on commit 72ba49e

Please sign in to comment.