Skip to content

Commit

Permalink
Support outputting arrays in protoc-gen-swagger (#853)
Browse files Browse the repository at this point in the history
* protoc-gen-swagger: add flag 'allow_repeated_fields_in_body'
Also added/updated tests for flags

* protoc-gen-swagger: updated response body example
Also:
* Added integration tests
* Added an extra cli test for parsing the flag
  • Loading branch information
abice authored and johanbrandhorst committed Jan 17, 2019
1 parent 20e8cf9 commit a0500cb
Show file tree
Hide file tree
Showing 20 changed files with 901 additions and 138 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -149,11 +149,11 @@ $(EXAMPLE_DEPSRCS): $(GO_PLUGIN) $(EXAMPLE_DEPS)

$(EXAMPLE_GWSRCS): ADDITIONAL_GW_FLAGS:=$(ADDITIONAL_GW_FLAGS),grpc_api_configuration=examples/proto/examplepb/unannotated_echo_service.yaml
$(EXAMPLE_GWSRCS): $(GATEWAY_PLUGIN) $(EXAMPLES)
protoc -I $(PROTOC_INC_PATH) -I. -I$(GOOGLEAPIS_DIR) --plugin=$(GATEWAY_PLUGIN) --grpc-gateway_out=logtostderr=true,$(PKGMAP)$(ADDITIONAL_GW_FLAGS):. $(EXAMPLES)
protoc -I $(PROTOC_INC_PATH) -I. -I$(GOOGLEAPIS_DIR) --plugin=$(GATEWAY_PLUGIN) --grpc-gateway_out=logtostderr=true,allow_repeated_fields_in_body=true,$(PKGMAP)$(ADDITIONAL_GW_FLAGS):. $(EXAMPLES)

$(EXAMPLE_SWAGGERSRCS): ADDITIONAL_SWG_FLAGS:=$(ADDITIONAL_SWG_FLAGS),grpc_api_configuration=examples/proto/examplepb/unannotated_echo_service.yaml
$(EXAMPLE_SWAGGERSRCS): $(SWAGGER_PLUGIN) $(SWAGGER_EXAMPLES)
protoc -I $(PROTOC_INC_PATH) -I. -I$(GOOGLEAPIS_DIR) --plugin=$(SWAGGER_PLUGIN) --swagger_out=logtostderr=true,$(PKGMAP)$(ADDITIONAL_SWG_FLAGS):. $(SWAGGER_EXAMPLES)
protoc -I $(PROTOC_INC_PATH) -I. -I$(GOOGLEAPIS_DIR) --plugin=$(SWAGGER_PLUGIN) --swagger_out=logtostderr=true,allow_repeated_fields_in_body=true,$(PKGMAP)$(ADDITIONAL_SWG_FLAGS):. $(SWAGGER_EXAMPLES)

$(ECHO_EXAMPLE_SRCS): $(ECHO_EXAMPLE_SPEC)
$(SWAGGER_CODEGEN) generate -i $(ECHO_EXAMPLE_SPEC) \
Expand Down
3 changes: 3 additions & 0 deletions examples/clients/responsebody/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ go_library(
"api_client.go",
"api_response.go",
"configuration.go",
"examplepb_repeated_response_body_out.go",
"examplepb_repeated_response_body_out_response.go",
"examplepb_repeated_response_strings.go",
"examplepb_response_body_message.go",
"examplepb_response_body_message_response.go",
"examplepb_response_body_out.go",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# ExamplepbRepeatedResponseBodyOut

## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**Response** | [**[]ExamplepbRepeatedResponseBodyOutResponse**](examplepbRepeatedResponseBodyOutResponse.md) | | [optional] [default to null]

[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)


Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# ExamplepbRepeatedResponseBodyOutResponse

## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**Data** | **string** | | [optional] [default to null]

[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)


Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# ExamplepbRepeatedResponseStrings

## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**Values** | **[]string** | | [optional] [default to null]

[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)


56 changes: 56 additions & 0 deletions examples/clients/responsebody/docs/ResponseBodyServiceApi.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ All URIs are relative to *http://localhost*
Method | HTTP request | Description
------------- | ------------- | -------------
[**GetResponseBody**](ResponseBodyServiceApi.md#GetResponseBody) | **Get** /responsebody/{data} |
[**ListResponseBodies**](ResponseBodyServiceApi.md#ListResponseBodies) | **Get** /responsebodies/{data} |
[**ListResponseStrings**](ResponseBodyServiceApi.md#ListResponseStrings) | **Get** /responsestrings/{data} |


# **GetResponseBody**
Expand Down Expand Up @@ -34,3 +36,57 @@ No authorization required

[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)

# **ListResponseBodies**
> []ExamplepbRepeatedResponseBodyOutResponse ListResponseBodies($data)



### Parameters

Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**data** | **string**| |

### Return type

[**[]ExamplepbRepeatedResponseBodyOutResponse**](examplepbRepeatedResponseBodyOutResponse.md)

### Authorization

No authorization required

### HTTP request headers

- **Content-Type**: application/json
- **Accept**: application/json

[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)

# **ListResponseStrings**
> []string ListResponseStrings($data)



### Parameters

Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**data** | **string**| |

### Return type

**[]string**

### Authorization

No authorization required

### HTTP request headers

- **Content-Type**: application/json
- **Accept**: application/json

[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* 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

type ExamplepbRepeatedResponseBodyOut struct {

Response []ExamplepbRepeatedResponseBodyOutResponse `json:"response,omitempty"`
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* 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

type ExamplepbRepeatedResponseBodyOutResponse struct {

Data string `json:"data,omitempty"`
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* 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

type ExamplepbRepeatedResponseStrings struct {

Values []string `json:"values,omitempty"`
}
120 changes: 120 additions & 0 deletions examples/clients/responsebody/response_body_service_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,123 @@ func (a ResponseBodyServiceApi) GetResponseBody(data string) (*ExamplepbResponse
return successPayload, localVarAPIResponse, err
}

/**
*
*
* @param data
* @return []ExamplepbRepeatedResponseBodyOutResponse
*/
func (a ResponseBodyServiceApi) ListResponseBodies(data string) ([]ExamplepbRepeatedResponseBodyOutResponse, *APIResponse, error) {

var localVarHttpMethod = strings.ToUpper("Get")
// create path and map variables
localVarPath := a.Configuration.BasePath + "/responsebodies/{data}"
localVarPath = strings.Replace(localVarPath, "{"+"data"+"}", fmt.Sprintf("%v", data), -1)

localVarHeaderParams := make(map[string]string)
localVarQueryParams := url.Values{}
localVarFormParams := make(map[string]string)
var localVarPostBody interface{}
var localVarFileName string
var localVarFileBytes []byte
// add default headers if any
for key := range a.Configuration.DefaultHeader {
localVarHeaderParams[key] = a.Configuration.DefaultHeader[key]
}

// to determine the Content-Type header
localVarHttpContentTypes := []string{ "application/json", }

// set Content-Type header
localVarHttpContentType := a.Configuration.APIClient.SelectHeaderContentType(localVarHttpContentTypes)
if localVarHttpContentType != "" {
localVarHeaderParams["Content-Type"] = localVarHttpContentType
}
// to determine the Accept header
localVarHttpHeaderAccepts := []string{
"application/json",
}

// set Accept header
localVarHttpHeaderAccept := a.Configuration.APIClient.SelectHeaderAccept(localVarHttpHeaderAccepts)
if localVarHttpHeaderAccept != "" {
localVarHeaderParams["Accept"] = localVarHttpHeaderAccept
}
var successPayload = new([]ExamplepbRepeatedResponseBodyOutResponse)
localVarHttpResponse, err := a.Configuration.APIClient.CallAPI(localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes)

var localVarURL, _ = url.Parse(localVarPath)
localVarURL.RawQuery = localVarQueryParams.Encode()
var localVarAPIResponse = &APIResponse{Operation: "ListResponseBodies", Method: localVarHttpMethod, RequestURL: localVarURL.String()}
if localVarHttpResponse != nil {
localVarAPIResponse.Response = localVarHttpResponse.RawResponse
localVarAPIResponse.Payload = localVarHttpResponse.Body()
}

if err != nil {
return *successPayload, localVarAPIResponse, err
}
err = json.Unmarshal(localVarHttpResponse.Body(), &successPayload)
return *successPayload, localVarAPIResponse, err
}

/**
*
*
* @param data
* @return []string
*/
func (a ResponseBodyServiceApi) ListResponseStrings(data string) ([]string, *APIResponse, error) {

var localVarHttpMethod = strings.ToUpper("Get")
// create path and map variables
localVarPath := a.Configuration.BasePath + "/responsestrings/{data}"
localVarPath = strings.Replace(localVarPath, "{"+"data"+"}", fmt.Sprintf("%v", data), -1)

localVarHeaderParams := make(map[string]string)
localVarQueryParams := url.Values{}
localVarFormParams := make(map[string]string)
var localVarPostBody interface{}
var localVarFileName string
var localVarFileBytes []byte
// add default headers if any
for key := range a.Configuration.DefaultHeader {
localVarHeaderParams[key] = a.Configuration.DefaultHeader[key]
}

// to determine the Content-Type header
localVarHttpContentTypes := []string{ "application/json", }

// set Content-Type header
localVarHttpContentType := a.Configuration.APIClient.SelectHeaderContentType(localVarHttpContentTypes)
if localVarHttpContentType != "" {
localVarHeaderParams["Content-Type"] = localVarHttpContentType
}
// to determine the Accept header
localVarHttpHeaderAccepts := []string{
"application/json",
}

// set Accept header
localVarHttpHeaderAccept := a.Configuration.APIClient.SelectHeaderAccept(localVarHttpHeaderAccepts)
if localVarHttpHeaderAccept != "" {
localVarHeaderParams["Accept"] = localVarHttpHeaderAccept
}
var successPayload = new([]string)
localVarHttpResponse, err := a.Configuration.APIClient.CallAPI(localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes)

var localVarURL, _ = url.Parse(localVarPath)
localVarURL.RawQuery = localVarQueryParams.Encode()
var localVarAPIResponse = &APIResponse{Operation: "ListResponseStrings", Method: localVarHttpMethod, RequestURL: localVarURL.String()}
if localVarHttpResponse != nil {
localVarAPIResponse.Response = localVarHttpResponse.RawResponse
localVarAPIResponse.Payload = localVarHttpResponse.Body()
}

if err != nil {
return *successPayload, localVarAPIResponse, err
}
err = json.Unmarshal(localVarHttpResponse.Body(), &successPayload)
return *successPayload, localVarAPIResponse, err
}

50 changes: 50 additions & 0 deletions examples/integration/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1307,6 +1307,8 @@ func TestResponseBody(t *testing.T) {
}

testResponseBody(t, 8080)
testResponseBodies(t, 8080)
testResponseStrings(t, 8080)
}

func testResponseBody(t *testing.T, port int) {
Expand All @@ -1332,3 +1334,51 @@ func testResponseBody(t *testing.T, port int) {
t.Errorf("response = %q; want %q", got, want)
}
}

func testResponseBodies(t *testing.T, port int) {
url := fmt.Sprintf("http://localhost:%d/responsebodies/foo", port)
resp, err := http.Get(url)
if err != nil {
t.Errorf("http.Get(%q) failed with %v; want success", url, err)
return
}
defer resp.Body.Close()
buf, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Errorf("ioutil.ReadAll(resp.Body) failed with %v; want success", err)
return
}

if got, want := resp.StatusCode, http.StatusOK; got != want {
t.Errorf("resp.StatusCode = %d; want %d", got, want)
t.Logf("%s", buf)
}

if got, want := string(buf), `[{"data":"foo"}]`; got != want {
t.Errorf("response = %q; want %q", got, want)
}
}

func testResponseStrings(t *testing.T, port int) {
url := fmt.Sprintf("http://localhost:%d/responsestrings/foo", port)
resp, err := http.Get(url)
if err != nil {
t.Errorf("http.Get(%q) failed with %v; want success", url, err)
return
}
defer resp.Body.Close()
buf, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Errorf("ioutil.ReadAll(resp.Body) failed with %v; want success", err)
return
}

if got, want := resp.StatusCode, http.StatusOK; got != want {
t.Errorf("resp.StatusCode = %d; want %d", got, want)
t.Logf("%s", buf)
}

if got, want := string(buf), `["hello","foo"]`; got != want {
t.Errorf("response = %q; want %q", got, want)
}
}
Loading

0 comments on commit a0500cb

Please sign in to comment.