diff --git a/encoding/form/proto_encode.go b/encoding/form/proto_encode.go index 67b92f92737..98469bb2f9a 100644 --- a/encoding/form/proto_encode.go +++ b/encoding/form/proto_encode.go @@ -168,7 +168,7 @@ func encodeMessage(msgDescriptor protoreflect.MessageDescriptor, value protorefl return "", nil } for i, v := range m.Paths { - m.Paths[i] = jsonCamelCase(v) + m.Paths[i] = JsonCamelCase(v) } return strings.Join(m.Paths, ","), nil default: @@ -198,10 +198,10 @@ func EncodeFieldMask(m protoreflect.Message) (query string) { return } -// jsonCamelCase converts a snake_case identifier to a camelCase identifier, +// JsonCamelCase converts a snake_case identifier to a camelCase identifier, // according to the protobuf JSON specification. // references: https://github.com/protocolbuffers/protobuf-go/blob/master/encoding/protojson/well_known_types.go#L842 -func jsonCamelCase(s string) string { +func JsonCamelCase(s string) string { var b []byte var wasUnderscore bool for i := 0; i < len(s); i++ { // proto identifiers are always ASCII diff --git a/encoding/form/proto_encode_test.go b/encoding/form/proto_encode_test.go index aa15b1fe89d..fc65306d4e4 100644 --- a/encoding/form/proto_encode_test.go +++ b/encoding/form/proto_encode_test.go @@ -72,7 +72,7 @@ func TestJsonCamelCase(t *testing.T) { } for _, test := range tests { t.Run(test.snakeCase, func(t *testing.T) { - camel := jsonCamelCase(test.snakeCase) + camel := JsonCamelCase(test.snakeCase) if camel != test.camelCase { t.Errorf("want: %s, got: %s", test.camelCase, camel) } diff --git a/transport/http/binding/encode.go b/transport/http/binding/encode.go index 5f12cf37071..884580c1203 100644 --- a/transport/http/binding/encode.go +++ b/transport/http/binding/encode.go @@ -18,18 +18,22 @@ func EncodeURL(pathTemplate string, msg interface{}, needQuery bool) string { } queryParams, _ := form.EncodeValues(msg) pathParams := make(map[string]struct{}) + protoMsg, isProtoMsg := msg.(proto.Message) path := reg.ReplaceAllStringFunc(pathTemplate, func(in string) string { // it's unreachable because the reg means that must have more than one char in {} // if len(in) < 4 { //nolint:gomnd // ** explain the 4 number here :-) ** // return in // } key := in[1 : len(in)-1] + if !queryParams.Has(key) && isProtoMsg { + key = form.JsonCamelCase(key) + } pathParams[key] = struct{}{} return queryParams.Get(key) }) if !needQuery { - if v, ok := msg.(proto.Message); ok { - if query := form.EncodeFieldMask(v.ProtoReflect()); query != "" { + if isProtoMsg { + if query := form.EncodeFieldMask(protoMsg.ProtoReflect()); query != "" { return path + "?" + query } } diff --git a/transport/http/binding/encode_test.go b/transport/http/binding/encode_test.go index 066e0624967..80cb01771b2 100644 --- a/transport/http/binding/encode_test.go +++ b/transport/http/binding/encode_test.go @@ -9,6 +9,7 @@ import ( ) func TestEncodeURL(t *testing.T) { + kratosName := "kratos" tests := []struct { pathTemplate string request *binding.HelloRequest @@ -117,6 +118,18 @@ func TestEncodeURL(t *testing.T) { needQuery: false, want: "http://helloworld.Greeter/helloworld/{}/[]/[kratos]", }, + { + pathTemplate: "http://helloworld.Greeter/helloworld/{optString}", + request: &binding.HelloRequest{OptString: &kratosName}, + needQuery: false, + want: "http://helloworld.Greeter/helloworld/kratos", + }, + { + pathTemplate: "http://helloworld.Greeter/helloworld/{opt_string}", + request: &binding.HelloRequest{OptString: &kratosName}, + needQuery: false, + want: "http://helloworld.Greeter/helloworld/kratos", + }, } for _, test := range tests {