Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support mapping bytes to []byte #489

Merged
merged 6 commits into from
Jan 11, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,6 @@ To use the same port for custom HTTP handlers (e.g. serving `swagger.json`), gRP

### Want to support
But not yet.
* bytes fields in path parameter. #5
* Optionally generating the entrypoint. #8
* `import_path` parameter

Expand Down
6 changes: 4 additions & 2 deletions examples/clients/abe/a_bit_of_everything_service_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,8 @@ func (a ABitOfEverythingServiceApi) GetMessageWithBody(id string, body Examplepb
* @param fixed32Value
* @param boolValue
* @param stringValue
* @param uint32Value TODO(yugui) add bytes_value.
* @param bytesValue
* @param uint32Value
* @param enumValue - ZERO: ZERO means 0 - ONE: ONE means 1
* @param sfixed32Value
* @param sfixed64Value
Expand All @@ -594,7 +595,7 @@ func (a ABitOfEverythingServiceApi) GetMessageWithBody(id string, body Examplepb
* @param repeatedEnumValue repeated enum value. it is comma-separated in query. - ZERO: ZERO means 0 - ONE: ONE means 1
* @return *ProtobufEmpty
*/
func (a ABitOfEverythingServiceApi) GetQuery(uuid string, singleNestedName string, singleNestedAmount int64, singleNestedOk string, floatValue float32, doubleValue float64, int64Value string, uint64Value string, int32Value int32, fixed64Value string, fixed32Value int64, boolValue bool, stringValue string, uint32Value int64, enumValue string, sfixed32Value int32, sfixed64Value string, sint32Value int32, sint64Value string, repeatedStringValue []string, oneofString string, nonConventionalNameValue string, timestampValue time.Time, repeatedEnumValue []string) (*ProtobufEmpty, *APIResponse, error) {
func (a ABitOfEverythingServiceApi) GetQuery(uuid string, singleNestedName string, singleNestedAmount int64, singleNestedOk string, floatValue float32, doubleValue float64, int64Value string, uint64Value string, int32Value int32, fixed64Value string, fixed32Value int64, boolValue bool, stringValue string, bytesValue string, uint32Value int64, enumValue string, sfixed32Value int32, sfixed64Value string, sint32Value int32, sint64Value string, repeatedStringValue []string, oneofString string, nonConventionalNameValue string, timestampValue time.Time, repeatedEnumValue []string) (*ProtobufEmpty, *APIResponse, error) {

var localVarHttpMethod = strings.ToUpper("Get")
// create path and map variables
Expand Down Expand Up @@ -623,6 +624,7 @@ func (a ABitOfEverythingServiceApi) GetQuery(uuid string, singleNestedName strin
localVarQueryParams.Add("fixed32_value", a.Configuration.APIClient.ParameterToString(fixed32Value, ""))
localVarQueryParams.Add("bool_value", a.Configuration.APIClient.ParameterToString(boolValue, ""))
localVarQueryParams.Add("string_value", a.Configuration.APIClient.ParameterToString(stringValue, ""))
localVarQueryParams.Add("bytes_value", a.Configuration.APIClient.ParameterToString(bytesValue, ""))
localVarQueryParams.Add("uint32_value", a.Configuration.APIClient.ParameterToString(uint32Value, ""))
localVarQueryParams.Add("enum_value", a.Configuration.APIClient.ParameterToString(enumValue, ""))
localVarQueryParams.Add("sfixed32_value", a.Configuration.APIClient.ParameterToString(sfixed32Value, ""))
Expand Down
2 changes: 2 additions & 0 deletions examples/clients/abe/examplepb_a_bit_of_everything.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ type ExamplepbABitOfEverything struct {

StringValue string `json:"string_value,omitempty"`

BytesValue string `json:"bytes_value,omitempty"`

Uint32Value int64 `json:"uint32_value,omitempty"`

EnumValue ExamplepbNumericEnum `json:"enum_value,omitempty"`
Expand Down
262 changes: 135 additions & 127 deletions examples/examplepb/a_bit_of_everything.pb.go

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions examples/examplepb/a_bit_of_everything.proto
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ option (grpc.gateway.protoc_gen_swagger.options.openapiv2_swagger) = {


// Intentionaly complicated message type to cover much features of Protobuf.
// NEXT ID: 27
// NEXT ID: 30
message ABitOfEverything {
option (grpc.gateway.protoc_gen_swagger.options.openapiv2_schema) = {
external_docs: {
Expand Down Expand Up @@ -72,7 +72,7 @@ message ABitOfEverything {
fixed32 fixed32_value = 9;
bool bool_value = 10;
string string_value = 11;
// TODO(yugui) add bytes_value
bytes bytes_value = 29;
uint32 uint32_value = 13;
NumericEnum enum_value = 14;
sfixed32 sfixed32_value = 15;
Expand Down
17 changes: 13 additions & 4 deletions examples/examplepb/a_bit_of_everything.swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,15 @@
"required": false,
"type": "string"
},
{
"name": "bytes_value",
"in": "query",
"required": false,
"type": "string",
"format": "byte"
},
{
"name": "uint32_value",
"description": "TODO(yugui) add bytes_value.",
"in": "query",
"required": false,
"type": "integer",
Expand Down Expand Up @@ -701,10 +707,13 @@
"string_value": {
"type": "string"
},
"bytes_value": {
"type": "string",
"format": "byte"
},
"uint32_value": {
"type": "integer",
"format": "int64",
"title": "TODO(yugui) add bytes_value"
"format": "int64"
},
"enum_value": {
"$ref": "#/definitions/examplepbNumericEnum"
Expand Down Expand Up @@ -770,7 +779,7 @@
"title": "repeated enum value. it is comma-separated in query"
}
},
"title": "Intentionaly complicated message type to cover much features of Protobuf.\nNEXT ID: 27",
"title": "Intentionaly complicated message type to cover much features of Protobuf.\nNEXT ID: 30",
"externalDocs": {
"description": "Find out more about ABitOfEverything",
"url": "https://github.com/grpc-ecosystem/grpc-gateway"
Expand Down
3 changes: 1 addition & 2 deletions protoc-gen-grpc-gateway/descriptor/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,8 +295,7 @@ var (
descriptor.FieldDescriptorProto_TYPE_STRING: "runtime.String",
// FieldDescriptorProto_TYPE_GROUP
// FieldDescriptorProto_TYPE_MESSAGE
// FieldDescriptorProto_TYPE_BYTES
// TODO(yugui) Handle bytes
descriptor.FieldDescriptorProto_TYPE_BYTES: "runtime.Bytes",
descriptor.FieldDescriptorProto_TYPE_UINT32: "runtime.Uint32",
// FieldDescriptorProto_TYPE_ENUM
// TODO(yugui) Handle Enum
Expand Down
11 changes: 11 additions & 0 deletions runtime/convert.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package runtime

import (
"encoding/base64"
"strconv"

"github.com/golang/protobuf/jsonpb"
Expand Down Expand Up @@ -61,6 +62,16 @@ func Uint32(val string) (uint32, error) {
return uint32(i), nil
}

// Bytes converts the given string representation of a byte sequence into a slice of bytes
// A bytes sequence is encoded in URL-safe base64 without padding
func Bytes(val string) ([]byte, error) {
b, err := base64.RawURLEncoding.DecodeString(val)
if err != nil {
return nil, err
}
return b, nil
}

// Timestamp converts the given RFC3339 formatted string into a timestamp.Timestamp.
func Timestamp(val string) (*timestamp.Timestamp, error) {
var r *timestamp.Timestamp
Expand Down
16 changes: 14 additions & 2 deletions runtime/query.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package runtime

import (
"encoding/base64"
"fmt"
"net/url"
"reflect"
Expand Down Expand Up @@ -64,10 +65,14 @@ func populateFieldValueFromPath(msg proto.Message, fieldPath []string, values []
}
m = f
case reflect.Slice:
// TODO(yugui) Support []byte
if !isLast {
return fmt.Errorf("unexpected repeated field in %s", strings.Join(fieldPath, "."))
}
// Handle []byte
if f.Type().Elem().Kind() == reflect.Uint8 {
m = f
break
}
return populateRepeatedField(f, values, props)
case reflect.Ptr:
if f.IsNil() {
Expand Down Expand Up @@ -203,6 +208,13 @@ func populateField(f reflect.Value, value string, props *proto.Properties) error
case "StringValue":
f.Field(0).SetString(value)
return nil
case "BytesValue":
bytesVal, err := base64.RawURLEncoding.DecodeString(value)
if err != nil {
return fmt.Errorf("bad BytesValue: %s", value)
}
f.Field(0).SetBytes(bytesVal)
return nil
}
}

Expand Down Expand Up @@ -274,6 +286,6 @@ var (
reflect.Int32: reflect.ValueOf(Int32),
reflect.Uint64: reflect.ValueOf(Uint64),
reflect.Uint32: reflect.ValueOf(Uint32),
// TODO(yugui) Support []byte
reflect.Slice: reflect.ValueOf(Bytes),
}
)
10 changes: 10 additions & 0 deletions runtime/query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ func TestPopulateParameters(t *testing.T) {
"uint32_value": {"4"},
"bool_value": {"true"},
"string_value": {"str"},
"bytes_value": {"Ynl0ZXM"},
"repeated_value": {"a", "b", "c"},
"enum_value": {"1"},
"repeated_enum": {"1", "2", "0"},
Expand All @@ -53,6 +54,7 @@ func TestPopulateParameters(t *testing.T) {
"wrapper_u_int32_value": {"4"},
"wrapper_bool_value": {"true"},
"wrapper_string_value": {"str"},
"wrapper_bytes_value": {"Ynl0ZXM"},
},
filter: utilities.NewDoubleArray(nil),
want: &proto3Message{
Expand All @@ -64,6 +66,7 @@ func TestPopulateParameters(t *testing.T) {
Uint32Value: 4,
BoolValue: true,
StringValue: "str",
BytesValue: []byte("bytes"),
RepeatedValue: []string{"a", "b", "c"},
EnumValue: EnumValue_Y,
RepeatedEnum: []EnumValue{EnumValue_Y, EnumValue_Z, EnumValue_X},
Expand All @@ -76,6 +79,7 @@ func TestPopulateParameters(t *testing.T) {
WrapperUInt32Value: &wrappers.UInt32Value{4},
WrapperBoolValue: &wrappers.BoolValue{true},
WrapperStringValue: &wrappers.StringValue{"str"},
WrapperBytesValue: &wrappers.BytesValue{[]byte("bytes")},
},
},
{
Expand All @@ -88,6 +92,7 @@ func TestPopulateParameters(t *testing.T) {
"uint32Value": {"4"},
"boolValue": {"true"},
"stringValue": {"str"},
"bytesValue": {"Ynl0ZXM"},
"repeatedValue": {"a", "b", "c"},
"enumValue": {"1"},
"repeatedEnum": {"1", "2", "0"},
Expand All @@ -100,6 +105,7 @@ func TestPopulateParameters(t *testing.T) {
"wrapperUInt32Value": {"4"},
"wrapperBoolValue": {"true"},
"wrapperStringValue": {"str"},
"wrapperBytesValue": {"Ynl0ZXM"},
},
filter: utilities.NewDoubleArray(nil),
want: &proto3Message{
Expand All @@ -111,6 +117,7 @@ func TestPopulateParameters(t *testing.T) {
Uint32Value: 4,
BoolValue: true,
StringValue: "str",
BytesValue: []byte("bytes"),
RepeatedValue: []string{"a", "b", "c"},
EnumValue: EnumValue_Y,
RepeatedEnum: []EnumValue{EnumValue_Y, EnumValue_Z, EnumValue_X},
Expand All @@ -123,6 +130,7 @@ func TestPopulateParameters(t *testing.T) {
WrapperUInt32Value: &wrappers.UInt32Value{4},
WrapperBoolValue: &wrappers.BoolValue{true},
WrapperStringValue: &wrappers.StringValue{"str"},
WrapperBytesValue: &wrappers.BytesValue{[]byte("bytes")},
},
},
{
Expand Down Expand Up @@ -471,6 +479,7 @@ type proto3Message struct {
Uint32Value uint32 `protobuf:"varint,7,opt,name=uint32_value,json=uint32Value" json:"uint32_value,omitempty"`
BoolValue bool `protobuf:"varint,8,opt,name=bool_value,json=boolValue" json:"bool_value,omitempty"`
StringValue string `protobuf:"bytes,9,opt,name=string_value,json=stringValue" json:"string_value,omitempty"`
BytesValue []byte `protobuf:"bytes,25,opt,name=bytes_value,json=bytesValue" json:"bytes_value,omitempty"`
RepeatedValue []string `protobuf:"bytes,10,rep,name=repeated_value,json=repeatedValue" json:"repeated_value,omitempty"`
EnumValue EnumValue `protobuf:"varint,11,opt,name=enum_value,json=enumValue,enum=runtime_test_api.EnumValue" json:"enum_value,omitempty"`
RepeatedEnum []EnumValue `protobuf:"varint,12,rep,packed,name=repeated_enum,json=repeatedEnum,enum=runtime_test_api.EnumValue" json:"repeated_enum,omitempty"`
Expand All @@ -484,6 +493,7 @@ type proto3Message struct {
WrapperUInt32Value *wrappers.UInt32Value `protobuf:"bytes,22,opt,name=wrapper_u_int32_value,json=wrapperUInt32Value" json:"wrapper_u_int32_value,omitempty"`
WrapperBoolValue *wrappers.BoolValue `protobuf:"bytes,23,opt,name=wrapper_bool_value,json=wrapperBoolValue" json:"wrapper_bool_value,omitempty"`
WrapperStringValue *wrappers.StringValue `protobuf:"bytes,24,opt,name=wrapper_string_value,json=wrapperStringValue" json:"wrapper_string_value,omitempty"`
WrapperBytesValue *wrappers.BytesValue `protobuf:"bytes,26,opt,name=wrapper_bytes_value,json=wrapperBytesValue" json:"wrapper_bytes_value,omitempty"`
}

func (m *proto3Message) Reset() { *m = proto3Message{} }
Expand Down