Skip to content

Commit 72ba49e

Browse files
committed
Add supporting response_body field in the google.api.HttpRule (#712)
Also: * add flag `allow_repeated_fields_in_body` in `protoc-gen-grpc-gateway` * add flag `json_names_for_fields` in `protoc-gen-swagger`
1 parent bb916ca commit 72ba49e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1351
-76
lines changed

Gopkg.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Gopkg.toml

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ required = [
2323
revision = "6724a57986aff9bff1a1770e9347036def7c89f6"
2424
name = "github.com/rogpeppe/fastuuid"
2525

26+
[[constraint]]
27+
# Also defined in WORKSPACE
28+
revision = "383e8b2c3b9e36c4076b235b32537292176bae20"
29+
name = "google.golang.org/genproto"
30+
2631
[[override]]
2732
# Also defined in WORKSPACE
2833
revision = "eb3733d160e74a9c7e442f435eb3bea458e1d19f"
@@ -48,12 +53,6 @@ required = [
4853
revision = "d11072e7ca9811b1100b80ca0269ac831f06d024"
4954
name = "google.golang.org/grpc"
5055

51-
[[constraint]]
52-
# Also defined in bazelbuild/rules_go
53-
# https://github.com/bazelbuild/rules_go/blob/436452edc29a2f1e0edc22d180fbb57c27e6d0af/go/private/repositories.bzl#L131
54-
revision = "86e600f69ee4704c6efbf6a2a40a5c10700e76c2"
55-
name = "google.golang.org/genproto"
56-
5756
[[constraint]]
5857
# Also defined in bazelbuild/rules_go
5958
# https://github.com/bazelbuild/rules_go/blob/436452edc29a2f1e0edc22d180fbb57c27e6d0af/go/private/repositories.bzl#L138

Makefile

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,17 @@ endif
6363
SWAGGER_EXAMPLES=examples/proto/examplepb/echo_service.proto \
6464
examples/proto/examplepb/a_bit_of_everything.proto \
6565
examples/proto/examplepb/wrappers.proto \
66-
examples/proto/examplepb/unannotated_echo_service.proto
66+
examples/proto/examplepb/unannotated_echo_service.proto \
67+
examples/proto/examplepb/response_body_service.proto
68+
6769
EXAMPLES=examples/proto/examplepb/echo_service.proto \
6870
examples/proto/examplepb/a_bit_of_everything.proto \
6971
examples/proto/examplepb/stream.proto \
7072
examples/proto/examplepb/flow_combination.proto \
7173
examples/proto/examplepb/wrappers.proto \
72-
examples/proto/examplepb/unannotated_echo_service.proto
74+
examples/proto/examplepb/unannotated_echo_service.proto \
75+
examples/proto/examplepb/response_body_service.proto
76+
7377
EXAMPLE_SVCSRCS=$(EXAMPLES:.proto=.pb.go)
7478
EXAMPLE_GWSRCS=$(EXAMPLES:.proto=.pb.gw.go)
7579
EXAMPLE_SWAGGERSRCS=$(SWAGGER_EXAMPLES:.proto=.swagger.json)
@@ -105,7 +109,14 @@ UNANNOTATED_ECHO_EXAMPLE_SRCS=$(EXAMPLE_CLIENT_DIR)/unannotatedecho/api_client.g
105109
$(EXAMPLE_CLIENT_DIR)/unannotatedecho/configuration.go \
106110
$(EXAMPLE_CLIENT_DIR)/unannotatedecho/examplepb_unannotated_simple_message.go \
107111
$(EXAMPLE_CLIENT_DIR)/unannotatedecho/unannotated_echo_service_api.go
108-
EXAMPLE_CLIENT_SRCS=$(ECHO_EXAMPLE_SRCS) $(ABE_EXAMPLE_SRCS) $(UNANNOTATED_ECHO_EXAMPLE_SRCS)
112+
RESPONSE_BODY_EXAMPLE_SPEC=examples/proto/examplepb/response_body_service.swagger.json
113+
RESPONSE_BODY_EXAMPLE_SRCS=$(EXAMPLE_CLIENT_DIR)/responsebody/api_client.go \
114+
$(EXAMPLE_CLIENT_DIR)/responsebody/api_response.go \
115+
$(EXAMPLE_CLIENT_DIR)/responsebody/configuration.go \
116+
$(EXAMPLE_CLIENT_DIR)/responsebody/examplepb_response_body.go \
117+
$(EXAMPLE_CLIENT_DIR)/responsebody/response_body_service_api.go
118+
119+
EXAMPLE_CLIENT_SRCS=$(ECHO_EXAMPLE_SRCS) $(ABE_EXAMPLE_SRCS) $(UNANNOTATED_ECHO_EXAMPLE_SRCS) $(RESPONSE_BODY_EXAMPLE_SRCS)
109120
SWAGGER_CODEGEN=swagger-codegen
110121

111122
PROTOC_INC_PATH=$(dir $(shell which protoc))/../include
@@ -164,6 +175,12 @@ $(UNANNOTATED_ECHO_EXAMPLE_SRCS): $(UNANNOTATED_ECHO_EXAMPLE_SPEC)
164175
@rm -f $(EXAMPLE_CLIENT_DIR)/unannotatedecho/README.md \
165176
$(EXAMPLE_CLIENT_DIR)/unannotatedecho/git_push.sh \
166177
$(EXAMPLE_CLIENT_DIR)/unannotatedecho/.travis.yml
178+
$(RESPONSE_BODY_EXAMPLE_SRCS): $(RESPONSE_BODY_EXAMPLE_SPEC)
179+
$(SWAGGER_CODEGEN) generate -i $(RESPONSE_BODY_EXAMPLE_SPEC) \
180+
-l go -o examples/clients/responsebody --additional-properties packageName=responsebody
181+
@rm -f $(EXAMPLE_CLIENT_DIR)/responsebody/README.md \
182+
$(EXAMPLE_CLIENT_DIR)/responsebody/git_push.sh \
183+
$(EXAMPLE_CLIENT_DIR)/responsebody/.travis.yml
167184

168185
examples: $(EXAMPLE_SVCSRCS) $(EXAMPLE_GWSRCS) $(EXAMPLE_DEPSRCS) $(EXAMPLE_SWAGGERSRCS) $(EXAMPLE_CLIENT_SRCS)
169186
test: examples

WORKSPACE

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,16 @@ http_archive(
1212
sha256 = "d03625db67e9fb0905bbd206fa97e32ae9da894fe234a493e7517fd25faec914",
1313
)
1414

15+
load("@io_bazel_rules_go//go:def.bzl", "go_repository")
16+
load("//:repositories.bzl", "repositories")
1517
load("@io_bazel_rules_go//go:def.bzl", "go_rules_dependencies", "go_register_toolchains")
1618

17-
go_rules_dependencies()
18-
19-
go_register_toolchains()
2019

21-
load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies")
22-
23-
gazelle_dependencies()
24-
25-
load("@io_bazel_rules_go//go:def.bzl", "go_repository")
20+
go_repository(
21+
name = "org_golang_google_genproto",
22+
commit = "383e8b2c3b9e36c4076b235b32537292176bae20",
23+
importpath = "google.golang.org/genproto",
24+
)
2625

2726
go_repository(
2827
name = "com_github_rogpeppe_fastuuid",
@@ -48,6 +47,12 @@ go_repository(
4847
importpath = "gopkg.in/yaml.v2",
4948
)
5049

51-
load("//:repositories.bzl", "repositories")
52-
5350
repositories()
51+
52+
go_rules_dependencies()
53+
54+
go_register_toolchains()
55+
56+
load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies")
57+
58+
gazelle_dependencies()
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Compiled Object files, Static and Dynamic libs (Shared Objects)
2+
*.o
3+
*.a
4+
*.so
5+
6+
# Folders
7+
_obj
8+
_test
9+
10+
# Architecture specific extensions/prefixes
11+
*.[568vq]
12+
[568vq].out
13+
14+
*.cgo1.go
15+
*.cgo2.c
16+
_cgo_defun.c
17+
_cgo_gotypes.go
18+
_cgo_export.*
19+
20+
_testmain.go
21+
22+
*.exe
23+
*.test
24+
*.prof
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Swagger Codegen Ignore
2+
# Generated by swagger-codegen https://github.com/swagger-api/swagger-codegen
3+
4+
# Use this file to prevent files from being overwritten by the generator.
5+
# The patterns follow closely to .gitignore or .dockerignore.
6+
7+
# As an example, the C# client generator defines ApiClient.cs.
8+
# You can make changes and tell Swagger Codgen to ignore just this file by uncommenting the following line:
9+
#ApiClient.cs
10+
11+
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
12+
#foo/*/qux
13+
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
14+
15+
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
16+
#foo/**/qux
17+
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
18+
19+
# You can also negate patterns with an exclamation (!).
20+
# For example, you can ignore all files in a docs folder with the file extension .md:
21+
#docs/*.md
22+
# Then explicitly reverse the ignore rule for a single file:
23+
#!docs/README.md
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
/*
2+
* examples/proto/examplepb/response_body_service.proto
3+
*
4+
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
5+
*
6+
* OpenAPI spec version: version not set
7+
*
8+
* Generated by: https://github.com/swagger-api/swagger-codegen.git
9+
*/
10+
11+
package responsebody
12+
13+
import (
14+
"bytes"
15+
"fmt"
16+
"path/filepath"
17+
"reflect"
18+
"strings"
19+
"net/url"
20+
"io/ioutil"
21+
"github.com/go-resty/resty"
22+
)
23+
24+
type APIClient struct {
25+
config *Configuration
26+
}
27+
28+
func (c *APIClient) SelectHeaderContentType(contentTypes []string) string {
29+
30+
if len(contentTypes) == 0 {
31+
return ""
32+
}
33+
if contains(contentTypes, "application/json") {
34+
return "application/json"
35+
}
36+
return contentTypes[0] // use the first content type specified in 'consumes'
37+
}
38+
39+
func (c *APIClient) SelectHeaderAccept(accepts []string) string {
40+
41+
if len(accepts) == 0 {
42+
return ""
43+
}
44+
if contains(accepts, "application/json") {
45+
return "application/json"
46+
}
47+
return strings.Join(accepts, ",")
48+
}
49+
50+
func contains(haystack []string, needle string) bool {
51+
for _, a := range haystack {
52+
if strings.ToLower(a) == strings.ToLower(needle) {
53+
return true
54+
}
55+
}
56+
return false
57+
}
58+
59+
func (c *APIClient) CallAPI(path string, method string,
60+
postBody interface{},
61+
headerParams map[string]string,
62+
queryParams url.Values,
63+
formParams map[string]string,
64+
fileName string,
65+
fileBytes []byte) (*resty.Response, error) {
66+
67+
rClient := c.prepareClient()
68+
request := c.prepareRequest(rClient, postBody, headerParams, queryParams, formParams, fileName, fileBytes)
69+
70+
switch strings.ToUpper(method) {
71+
case "GET":
72+
response, err := request.Get(path)
73+
return response, err
74+
case "POST":
75+
response, err := request.Post(path)
76+
return response, err
77+
case "PUT":
78+
response, err := request.Put(path)
79+
return response, err
80+
case "PATCH":
81+
response, err := request.Patch(path)
82+
return response, err
83+
case "DELETE":
84+
response, err := request.Delete(path)
85+
return response, err
86+
}
87+
88+
return nil, fmt.Errorf("invalid method %v", method)
89+
}
90+
91+
func (c *APIClient) ParameterToString(obj interface{}, collectionFormat string) string {
92+
delimiter := ""
93+
switch collectionFormat {
94+
case "pipes":
95+
delimiter = "|"
96+
case "ssv":
97+
delimiter = " "
98+
case "tsv":
99+
delimiter = "\t"
100+
case "csv":
101+
delimiter = ","
102+
}
103+
104+
if reflect.TypeOf(obj).Kind() == reflect.Slice {
105+
return strings.Trim(strings.Replace(fmt.Sprint(obj), " ", delimiter, -1), "[]")
106+
}
107+
108+
return fmt.Sprintf("%v", obj)
109+
}
110+
111+
func (c *APIClient) prepareClient() *resty.Client {
112+
113+
rClient := resty.New()
114+
115+
rClient.SetDebug(c.config.Debug)
116+
if c.config.Transport != nil {
117+
rClient.SetTransport(c.config.Transport)
118+
}
119+
120+
if c.config.Timeout != nil {
121+
rClient.SetTimeout(*c.config.Timeout)
122+
}
123+
rClient.SetLogger(ioutil.Discard)
124+
return rClient
125+
}
126+
127+
func (c *APIClient) prepareRequest(
128+
rClient *resty.Client,
129+
postBody interface{},
130+
headerParams map[string]string,
131+
queryParams url.Values,
132+
formParams map[string]string,
133+
fileName string,
134+
fileBytes []byte) *resty.Request {
135+
136+
137+
request := rClient.R()
138+
request.SetBody(postBody)
139+
140+
if c.config.UserAgent != "" {
141+
request.SetHeader("User-Agent", c.config.UserAgent)
142+
}
143+
144+
// add header parameter, if any
145+
if len(headerParams) > 0 {
146+
request.SetHeaders(headerParams)
147+
}
148+
149+
// add query parameter, if any
150+
if len(queryParams) > 0 {
151+
request.SetMultiValueQueryParams(queryParams)
152+
}
153+
154+
// add form parameter, if any
155+
if len(formParams) > 0 {
156+
request.SetFormData(formParams)
157+
}
158+
159+
if len(fileBytes) > 0 && fileName != "" {
160+
_, fileNm := filepath.Split(fileName)
161+
request.SetFileReader("file", fileNm, bytes.NewReader(fileBytes))
162+
}
163+
return request
164+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* examples/proto/examplepb/response_body_service.proto
3+
*
4+
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
5+
*
6+
* OpenAPI spec version: version not set
7+
*
8+
* Generated by: https://github.com/swagger-api/swagger-codegen.git
9+
*/
10+
11+
package responsebody
12+
13+
import (
14+
"net/http"
15+
)
16+
17+
type APIResponse struct {
18+
*http.Response `json:"-"`
19+
Message string `json:"message,omitempty"`
20+
// Operation is the name of the swagger operation.
21+
Operation string `json:"operation,omitempty"`
22+
// RequestURL is the request URL. This value is always available, even if the
23+
// embedded *http.Response is nil.
24+
RequestURL string `json:"url,omitempty"`
25+
// Method is the HTTP method used for the request. This value is always
26+
// available, even if the embedded *http.Response is nil.
27+
Method string `json:"method,omitempty"`
28+
// Payload holds the contents of the response body (which may be nil or empty).
29+
// This is provided here as the raw response.Body() reader will have already
30+
// been drained.
31+
Payload []byte `json:"-"`
32+
}
33+
34+
func NewAPIResponse(r *http.Response) *APIResponse {
35+
36+
response := &APIResponse{Response: r}
37+
return response
38+
}
39+
40+
func NewAPIResponseWithError(errorMessage string) *APIResponse {
41+
42+
response := &APIResponse{Message: errorMessage}
43+
return response
44+
}

0 commit comments

Comments
 (0)