Skip to content

Commit 936b4c8

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 936b4c8

40 files changed

+1329
-61
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: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ required = [
5151
[[constraint]]
5252
# Also defined in bazelbuild/rules_go
5353
# https://github.com/bazelbuild/rules_go/blob/436452edc29a2f1e0edc22d180fbb57c27e6d0af/go/private/repositories.bzl#L131
54-
revision = "86e600f69ee4704c6efbf6a2a40a5c10700e76c2"
54+
revision = "383e8b2c3b9e36c4076b235b32537292176bae20"
5555
name = "google.golang.org/genproto"
5656

5757
[[constraint]]

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
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+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
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+
"encoding/base64"
15+
"net/http"
16+
"time"
17+
)
18+
19+
20+
type Configuration struct {
21+
Username string `json:"userName,omitempty"`
22+
Password string `json:"password,omitempty"`
23+
APIKeyPrefix map[string]string `json:"APIKeyPrefix,omitempty"`
24+
APIKey map[string]string `json:"APIKey,omitempty"`
25+
Debug bool `json:"debug,omitempty"`
26+
DebugFile string `json:"debugFile,omitempty"`
27+
OAuthToken string `json:"oAuthToken,omitempty"`
28+
BasePath string `json:"basePath,omitempty"`
29+
Host string `json:"host,omitempty"`
30+
Scheme string `json:"scheme,omitempty"`
31+
AccessToken string `json:"accessToken,omitempty"`
32+
DefaultHeader map[string]string `json:"defaultHeader,omitempty"`
33+
UserAgent string `json:"userAgent,omitempty"`
34+
APIClient *APIClient
35+
Transport *http.Transport
36+
Timeout *time.Duration `json:"timeout,omitempty"`
37+
}
38+
39+
func NewConfiguration() *Configuration {
40+
cfg := &Configuration{
41+
BasePath: "http://localhost",
42+
DefaultHeader: make(map[string]string),
43+
APIKey: make(map[string]string),
44+
APIKeyPrefix: make(map[string]string),
45+
UserAgent: "Swagger-Codegen/1.0.0/go",
46+
APIClient: &APIClient{},
47+
}
48+
49+
cfg.APIClient.config = cfg
50+
return cfg
51+
}
52+
53+
func (c *Configuration) GetBasicAuthEncodedString() string {
54+
return base64.StdEncoding.EncodeToString([]byte(c.Username + ":" + c.Password))
55+
}
56+
57+
func (c *Configuration) AddDefaultHeader(key string, value string) {
58+
c.DefaultHeader[key] = value
59+
}
60+
61+
func (c *Configuration) GetAPIKeyWithPrefix(APIKeyIdentifier string) string {
62+
if c.APIKeyPrefix[APIKeyIdentifier] != "" {
63+
return c.APIKeyPrefix[APIKeyIdentifier] + " " + c.APIKey[APIKeyIdentifier]
64+
}
65+
66+
return c.APIKey[APIKeyIdentifier]
67+
}

0 commit comments

Comments
 (0)