Skip to content

Commit

Permalink
Added support for path param repeated primitive fields
Browse files Browse the repository at this point in the history
Added conversion functions for repeated path params
Updated bytes converter to support URL encoded base64 strings

Added support for repeated primitive path params in protoc-gen-grpc-gateway
Added support for repeated primitive path params in protoc-gen-swagger
Added --repeated_path_param_separator cmd line param to support setting separator to `csv`, `ssv`, `pipes` and `tsv`

Re-generated examples
Added ABitOfEverythingRepeated to validate repeated path parameter functionality
Added GetRepeatedQuery rpc endpoint
Updated browser tests to test GetRepeatedQuery rpc endpoint
Updated integration tests to test GetRepeatedQuery rpc endpoint
Added GetRepeatedQuery to ABitOfEverythingServer implementation

Added missing reflect.DeepEqual test

Change separator type from string to rune
Fixed slice duplication in string slice conversion method
Reverted --allowRepeatedFieldsInBody in swagger generator
Changed TODO of bytes slice proto2 function

Corrected if-statement releated to repeated fields in resolveFieldPath function

Rebase
  • Loading branch information
Marcus Rosén authored and johanbrandhorst committed Sep 1, 2018
1 parent 0e59487 commit ab0345b
Show file tree
Hide file tree
Showing 20 changed files with 1,651 additions and 200 deletions.
36 changes: 36 additions & 0 deletions examples/browser/a_bit_of_everything_service.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -187,5 +187,41 @@ describe('ABitOfEverythingService', function() {
}).finally(done);
});
});

describe('GetRepeatedQuery', function() {
var repeated;
var expected = {
path_repeated_float_value: [1.5, -1.5],
path_repeated_double_value: [2.5, -2.5],
path_repeated_int64_value: ["4294967296", "-4294967296"],
path_repeated_uint64_value: ["0", "9223372036854775807"],
path_repeated_int32_value: [2147483647, -2147483648],
path_repeated_fixed64_value: ["0", "9223372036854775807"],
path_repeated_fixed32_value: [0, 4294967295],
path_repeated_bool_value: [true, false],
path_repeated_string_value: ["foo", "bar"],
path_repeated_bytes_value: ["AA==", "_w=="],
path_repeated_uint32_value: [4294967295, 0],
path_repeated_enum_value: ["ONE", "ONE"],
path_repeated_sfixed32_value: [-2147483648, 2147483647],
path_repeated_sfixed64_value: ["-4294967296", "4294967296"],
path_repeated_sint32_value: [2147483646, -2147483647],
path_repeated_sint64_value: ["4611686018427387903", "-4611686018427387904"]
};

beforeEach(function(done) {
client.ABitOfEverythingService.GetRepeatedQuery(expected).then(function(resp) {
repeated = resp.obj;
}).catch(function(err) {
done.fail(err);
}).then(done);
});

it('should echo the request back', function() {
// API will echo a non URL safe encoding
expected.path_repeated_bytes_value = ["AA==", "/w=="];
expect(repeated).toEqual(expected);
});
});
});

1 change: 1 addition & 0 deletions examples/clients/abe/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ go_library(
"echo_service_api.go",
"enum_helper.go",
"examplepb_a_bit_of_everything.go",
"examplepb_a_bit_of_everything_repeated.go",
"examplepb_body.go",
"examplepb_numeric_enum.go",
"message_path_enum_nested_path_enum.go",
Expand Down
104 changes: 104 additions & 0 deletions examples/clients/abe/a_bit_of_everything_service_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,110 @@ func (a ABitOfEverythingServiceApi) GetQuery(uuid string, singleNestedName strin
return successPayload, localVarAPIResponse, err
}

/**
*
*
* @param pathRepeatedFloatValue repeated values. they are comma-separated in path
* @param pathRepeatedDoubleValue
* @param pathRepeatedInt64Value
* @param pathRepeatedUint64Value
* @param pathRepeatedInt32Value
* @param pathRepeatedFixed64Value
* @param pathRepeatedFixed32Value
* @param pathRepeatedBoolValue
* @param pathRepeatedStringValue
* @param pathRepeatedBytesValue
* @param pathRepeatedUint32Value
* @param pathRepeatedEnumValue
* @param pathRepeatedSfixed32Value
* @param pathRepeatedSfixed64Value
* @param pathRepeatedSint32Value
* @param pathRepeatedSint64Value
* @return *ExamplepbABitOfEverythingRepeated
*/
func (a ABitOfEverythingServiceApi) GetRepeatedQuery(pathRepeatedFloatValue []float32, pathRepeatedDoubleValue []float64, pathRepeatedInt64Value []string, pathRepeatedUint64Value []string, pathRepeatedInt32Value []int32, pathRepeatedFixed64Value []string, pathRepeatedFixed32Value []int64, pathRepeatedBoolValue []bool, pathRepeatedStringValue []string, pathRepeatedBytesValue []string, pathRepeatedUint32Value []int64, pathRepeatedEnumValue []string, pathRepeatedSfixed32Value []int32, pathRepeatedSfixed64Value []string, pathRepeatedSint32Value []int32, pathRepeatedSint64Value []string) (*ExamplepbABitOfEverythingRepeated, *APIResponse, error) {

var localVarHttpMethod = strings.ToUpper("Get")
// create path and map variables
localVarPath := a.Configuration.BasePath + "/v1/example/a_bit_of_everything_repeated/{path_repeated_float_value}/{path_repeated_double_value}/{path_repeated_int64_value}/{path_repeated_uint64_value}/{path_repeated_int32_value}/{path_repeated_fixed64_value}/{path_repeated_fixed32_value}/{path_repeated_bool_value}/{path_repeated_string_value}/{path_repeated_bytes_value}/{path_repeated_uint32_value}/{path_repeated_enum_value}/{path_repeated_sfixed32_value}/{path_repeated_sfixed64_value}/{path_repeated_sint32_value}/{path_repeated_sint64_value}"
localVarPath = strings.Replace(localVarPath, "{"+"path_repeated_float_value"+"}", fmt.Sprintf("%v", pathRepeatedFloatValue), -1)
localVarPath = strings.Replace(localVarPath, "{"+"path_repeated_double_value"+"}", fmt.Sprintf("%v", pathRepeatedDoubleValue), -1)
localVarPath = strings.Replace(localVarPath, "{"+"path_repeated_int64_value"+"}", fmt.Sprintf("%v", pathRepeatedInt64Value), -1)
localVarPath = strings.Replace(localVarPath, "{"+"path_repeated_uint64_value"+"}", fmt.Sprintf("%v", pathRepeatedUint64Value), -1)
localVarPath = strings.Replace(localVarPath, "{"+"path_repeated_int32_value"+"}", fmt.Sprintf("%v", pathRepeatedInt32Value), -1)
localVarPath = strings.Replace(localVarPath, "{"+"path_repeated_fixed64_value"+"}", fmt.Sprintf("%v", pathRepeatedFixed64Value), -1)
localVarPath = strings.Replace(localVarPath, "{"+"path_repeated_fixed32_value"+"}", fmt.Sprintf("%v", pathRepeatedFixed32Value), -1)
localVarPath = strings.Replace(localVarPath, "{"+"path_repeated_bool_value"+"}", fmt.Sprintf("%v", pathRepeatedBoolValue), -1)
localVarPath = strings.Replace(localVarPath, "{"+"path_repeated_string_value"+"}", fmt.Sprintf("%v", pathRepeatedStringValue), -1)
localVarPath = strings.Replace(localVarPath, "{"+"path_repeated_bytes_value"+"}", fmt.Sprintf("%v", pathRepeatedBytesValue), -1)
localVarPath = strings.Replace(localVarPath, "{"+"path_repeated_uint32_value"+"}", fmt.Sprintf("%v", pathRepeatedUint32Value), -1)
localVarPath = strings.Replace(localVarPath, "{"+"path_repeated_enum_value"+"}", fmt.Sprintf("%v", pathRepeatedEnumValue), -1)
localVarPath = strings.Replace(localVarPath, "{"+"path_repeated_sfixed32_value"+"}", fmt.Sprintf("%v", pathRepeatedSfixed32Value), -1)
localVarPath = strings.Replace(localVarPath, "{"+"path_repeated_sfixed64_value"+"}", fmt.Sprintf("%v", pathRepeatedSfixed64Value), -1)
localVarPath = strings.Replace(localVarPath, "{"+"path_repeated_sint32_value"+"}", fmt.Sprintf("%v", pathRepeatedSint32Value), -1)
localVarPath = strings.Replace(localVarPath, "{"+"path_repeated_sint64_value"+"}", fmt.Sprintf("%v", pathRepeatedSint64Value), -1)

localVarHeaderParams := make(map[string]string)
localVarQueryParams := url.Values{}
localVarFormParams := make(map[string]string)
var localVarPostBody interface{}
var localVarFileName string
var localVarFileBytes []byte
// authentication '(OAuth2)' required
// oauth required
if a.Configuration.AccessToken != ""{
localVarHeaderParams["Authorization"] = "Bearer " + a.Configuration.AccessToken
}
// authentication '(BasicAuth)' required
// http basic authentication required
if a.Configuration.Username != "" || a.Configuration.Password != ""{
localVarHeaderParams["Authorization"] = "Basic " + a.Configuration.GetBasicAuthEncodedString()
}
// authentication '(ApiKeyAuth)' required
// set key with prefix in header
localVarHeaderParams["X-API-Key"] = a.Configuration.GetAPIKeyWithPrefix("X-API-Key")
// 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", "application/x-foo-mime", }

// 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",
"application/x-foo-mime",
}

// set Accept header
localVarHttpHeaderAccept := a.Configuration.APIClient.SelectHeaderAccept(localVarHttpHeaderAccepts)
if localVarHttpHeaderAccept != "" {
localVarHeaderParams["Accept"] = localVarHttpHeaderAccept
}
var successPayload = new(ExamplepbABitOfEverythingRepeated)
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: "GetRepeatedQuery", 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
}

/**
*
*
Expand Down
46 changes: 46 additions & 0 deletions examples/clients/abe/examplepb_a_bit_of_everything_repeated.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* A Bit of Everything
*
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
*
* OpenAPI spec version: 1.0
* Contact: none@example.com
* Generated by: https://github.com/swagger-api/swagger-codegen.git
*/

package abe

type ExamplepbABitOfEverythingRepeated struct {

PathRepeatedFloatValue []float32 `json:"path_repeated_float_value,omitempty"`

PathRepeatedDoubleValue []float64 `json:"path_repeated_double_value,omitempty"`

PathRepeatedInt64Value []string `json:"path_repeated_int64_value,omitempty"`

PathRepeatedUint64Value []string `json:"path_repeated_uint64_value,omitempty"`

PathRepeatedInt32Value []int32 `json:"path_repeated_int32_value,omitempty"`

PathRepeatedFixed64Value []string `json:"path_repeated_fixed64_value,omitempty"`

PathRepeatedFixed32Value []int64 `json:"path_repeated_fixed32_value,omitempty"`

PathRepeatedBoolValue []bool `json:"path_repeated_bool_value,omitempty"`

PathRepeatedStringValue []string `json:"path_repeated_string_value,omitempty"`

PathRepeatedBytesValue []string `json:"path_repeated_bytes_value,omitempty"`

PathRepeatedUint32Value []int64 `json:"path_repeated_uint32_value,omitempty"`

PathRepeatedEnumValue []ExamplepbNumericEnum `json:"path_repeated_enum_value,omitempty"`

PathRepeatedSfixed32Value []int32 `json:"path_repeated_sfixed32_value,omitempty"`

PathRepeatedSfixed64Value []string `json:"path_repeated_sfixed64_value,omitempty"`

PathRepeatedSint32Value []int32 `json:"path_repeated_sint32_value,omitempty"`

PathRepeatedSint64Value []string `json:"path_repeated_sint64_value,omitempty"`
}
121 changes: 121 additions & 0 deletions examples/integration/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package integration_test
import (
"bytes"
"context"
"encoding/base64"
"encoding/json"
"fmt"
"io"
Expand Down Expand Up @@ -266,6 +267,7 @@ func TestABE(t *testing.T) {
testABEBulkEcho(t, 8080)
testABEBulkEchoZeroLength(t, 8080)
testAdditionalBindings(t, 8080)
testABERepeated(t, 8080)
}

func testABECreate(t *testing.T, port int) {
Expand Down Expand Up @@ -835,6 +837,125 @@ func testAdditionalBindings(t *testing.T, port int) {
}
}

func testABERepeated(t *testing.T, port int) {
f := func(v reflect.Value) string {
var f func(v reflect.Value, idx int) string
s := make([]string, v.Len())
switch v.Index(0).Kind() {
case reflect.Slice:
f = func(v reflect.Value, idx int) string {
t := v.Index(idx).Type().Elem().Kind()
if t == reflect.Uint8 {
return base64.URLEncoding.EncodeToString(v.Index(idx).Interface().([]byte))
}
// Could handle more elegantly
panic("unknown slice of type: " + t.String())
}
default:
f = func(v reflect.Value, idx int) string {
return fmt.Sprintf("%v", v.Index(idx).Interface())
}
}
for i := 0; i < v.Len(); i++ {
s[i] = f(v, i)
}
return strings.Join(s, ",")
}
want := gw.ABitOfEverythingRepeated{
PathRepeatedFloatValue: []float32{
1.5,
-1.5,
},
PathRepeatedDoubleValue: []float64{
2.5,
-2.5,
},
PathRepeatedInt64Value: []int64{
4294967296,
-4294967296,
},
PathRepeatedUint64Value: []uint64{
0,
9223372036854775807,
},
PathRepeatedInt32Value: []int32{
2147483647,
-2147483648,
},
PathRepeatedFixed64Value: []uint64{
0,
9223372036854775807,
},
PathRepeatedFixed32Value: []uint32{
0,
4294967295,
},
PathRepeatedBoolValue: []bool{
true,
false,
},
PathRepeatedStringValue: []string{
"foo",
"bar",
},
PathRepeatedBytesValue: [][]byte{
[]byte{0x00},
[]byte{0xFF},
},
PathRepeatedUint32Value: []uint32{
0,
4294967295,
},
PathRepeatedEnumValue: []gw.NumericEnum{
gw.NumericEnum_ZERO,
gw.NumericEnum_ONE,
},
PathRepeatedSfixed32Value: []int32{
2147483647,
-2147483648,
},
PathRepeatedSfixed64Value: []int64{
4294967296,
-4294967296,
},
PathRepeatedSint32Value: []int32{
2147483647,
-2147483648,
},
PathRepeatedSint64Value: []int64{
4611686018427387903,
-4611686018427387904,
},
}
url := fmt.Sprintf("http://localhost:%d/v1/example/a_bit_of_everything_repeated/%s/%s/%s/%s/%s/%s/%s/%s/%s/%s/%s/%s/%s/%s/%s/%s", port, f(reflect.ValueOf(want.PathRepeatedFloatValue)), f(reflect.ValueOf(want.PathRepeatedDoubleValue)), f(reflect.ValueOf(want.PathRepeatedInt64Value)), f(reflect.ValueOf(want.PathRepeatedUint64Value)), f(reflect.ValueOf(want.PathRepeatedInt32Value)), f(reflect.ValueOf(want.PathRepeatedFixed64Value)), f(reflect.ValueOf(want.PathRepeatedFixed32Value)), f(reflect.ValueOf(want.PathRepeatedBoolValue)), f(reflect.ValueOf(want.PathRepeatedStringValue)), f(reflect.ValueOf(want.PathRepeatedBytesValue)), f(reflect.ValueOf(want.PathRepeatedUint32Value)), f(reflect.ValueOf(want.PathRepeatedEnumValue)), f(reflect.ValueOf(want.PathRepeatedSfixed32Value)), f(reflect.ValueOf(want.PathRepeatedSfixed64Value)), f(reflect.ValueOf(want.PathRepeatedSint32Value)), f(reflect.ValueOf(want.PathRepeatedSint64Value)))

resp, err := http.Get(url)
if err != nil {
t.Errorf("http.Post(%q) failed with %v; want success", url, err)
return
}
defer resp.Body.Close()
buf, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Errorf("iotuil.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)
}

var msg gw.ABitOfEverythingRepeated
if err := jsonpb.UnmarshalString(string(buf), &msg); err != nil {
t.Errorf("jsonpb.UnmarshalString(%s, &msg) failed with %v; want success", buf, err)
return
}
if got := msg; !reflect.DeepEqual(got, want) {
t.Errorf("msg= %v; want %v", &got, &want)
}
}

func TestTimeout(t *testing.T) {
url := "http://localhost:8080/v2/example/timeout"
req, err := http.NewRequest("GET", url, nil)
Expand Down
Loading

0 comments on commit ab0345b

Please sign in to comment.