From eb958b2093f8c3226f8828062666fd58cb00924c Mon Sep 17 00:00:00 2001 From: longxboy Date: Wed, 26 May 2021 14:23:43 +0800 Subject: [PATCH] add path for rpc stub (#947) * add path for rpc stub * fix http body and response_body Co-authored-by: chenzhihui --- api/metadata/metadata.pb.go | 162 +++++----- api/metadata/metadata_grpc.pb.go | 2 +- api/metadata/metadata_http.pb.go | 95 +++++- cmd/protoc-gen-go-http/http.go | 12 +- cmd/protoc-gen-go-http/template.go | 46 ++- .../helloworld/helloworld_http.pb.go | 42 ++- examples/http/handler/main.go | 4 +- examples/proto/echo_service.pb.go | 92 +++--- examples/proto/echo_service.proto | 1 + examples/proto/echo_service_http.pb.go | 295 ++++++++++++++++-- examples/proto/echo_service_test.go | 17 +- examples/proto/stream.pb.go | 13 +- examples/proto/stream_grpc.pb.go | 12 +- examples/proto/stream_http.pb.go | 4 + transport/http/binding/encode.go | 231 ++++++++++++++ transport/http/binding/proto.go | 41 --- transport/http/binding/proto_test.go | 8 +- transport/http/calloption.go | 33 +- transport/http/client.go | 20 +- transport/http/handle.go | 4 - 20 files changed, 847 insertions(+), 287 deletions(-) create mode 100644 transport/http/binding/encode.go diff --git a/api/metadata/metadata.pb.go b/api/metadata/metadata.pb.go index a5e2067b7..a0160e78e 100644 --- a/api/metadata/metadata.pb.go +++ b/api/metadata/metadata.pb.go @@ -2,7 +2,7 @@ // versions: // protoc-gen-go v1.26.0 // protoc v3.14.0 -// source: metadata.proto +// source: metadata/metadata.proto package metadata @@ -31,7 +31,7 @@ type ListServicesRequest struct { func (x *ListServicesRequest) Reset() { *x = ListServicesRequest{} if protoimpl.UnsafeEnabled { - mi := &file_metadata_proto_msgTypes[0] + mi := &file_metadata_metadata_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -44,7 +44,7 @@ func (x *ListServicesRequest) String() string { func (*ListServicesRequest) ProtoMessage() {} func (x *ListServicesRequest) ProtoReflect() protoreflect.Message { - mi := &file_metadata_proto_msgTypes[0] + mi := &file_metadata_metadata_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -57,7 +57,7 @@ func (x *ListServicesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListServicesRequest.ProtoReflect.Descriptor instead. func (*ListServicesRequest) Descriptor() ([]byte, []int) { - return file_metadata_proto_rawDescGZIP(), []int{0} + return file_metadata_metadata_proto_rawDescGZIP(), []int{0} } type ListServicesReply struct { @@ -72,7 +72,7 @@ type ListServicesReply struct { func (x *ListServicesReply) Reset() { *x = ListServicesReply{} if protoimpl.UnsafeEnabled { - mi := &file_metadata_proto_msgTypes[1] + mi := &file_metadata_metadata_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -85,7 +85,7 @@ func (x *ListServicesReply) String() string { func (*ListServicesReply) ProtoMessage() {} func (x *ListServicesReply) ProtoReflect() protoreflect.Message { - mi := &file_metadata_proto_msgTypes[1] + mi := &file_metadata_metadata_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -98,7 +98,7 @@ func (x *ListServicesReply) ProtoReflect() protoreflect.Message { // Deprecated: Use ListServicesReply.ProtoReflect.Descriptor instead. func (*ListServicesReply) Descriptor() ([]byte, []int) { - return file_metadata_proto_rawDescGZIP(), []int{1} + return file_metadata_metadata_proto_rawDescGZIP(), []int{1} } func (x *ListServicesReply) GetServices() []string { @@ -126,7 +126,7 @@ type GetServiceDescRequest struct { func (x *GetServiceDescRequest) Reset() { *x = GetServiceDescRequest{} if protoimpl.UnsafeEnabled { - mi := &file_metadata_proto_msgTypes[2] + mi := &file_metadata_metadata_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -139,7 +139,7 @@ func (x *GetServiceDescRequest) String() string { func (*GetServiceDescRequest) ProtoMessage() {} func (x *GetServiceDescRequest) ProtoReflect() protoreflect.Message { - mi := &file_metadata_proto_msgTypes[2] + mi := &file_metadata_metadata_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -152,7 +152,7 @@ func (x *GetServiceDescRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetServiceDescRequest.ProtoReflect.Descriptor instead. func (*GetServiceDescRequest) Descriptor() ([]byte, []int) { - return file_metadata_proto_rawDescGZIP(), []int{2} + return file_metadata_metadata_proto_rawDescGZIP(), []int{2} } func (x *GetServiceDescRequest) GetName() string { @@ -173,7 +173,7 @@ type GetServiceDescReply struct { func (x *GetServiceDescReply) Reset() { *x = GetServiceDescReply{} if protoimpl.UnsafeEnabled { - mi := &file_metadata_proto_msgTypes[3] + mi := &file_metadata_metadata_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -186,7 +186,7 @@ func (x *GetServiceDescReply) String() string { func (*GetServiceDescReply) ProtoMessage() {} func (x *GetServiceDescReply) ProtoReflect() protoreflect.Message { - mi := &file_metadata_proto_msgTypes[3] + mi := &file_metadata_metadata_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -199,7 +199,7 @@ func (x *GetServiceDescReply) ProtoReflect() protoreflect.Message { // Deprecated: Use GetServiceDescReply.ProtoReflect.Descriptor instead. func (*GetServiceDescReply) Descriptor() ([]byte, []int) { - return file_metadata_proto_rawDescGZIP(), []int{3} + return file_metadata_metadata_proto_rawDescGZIP(), []int{3} } func (x *GetServiceDescReply) GetFileDescSet() *descriptorpb.FileDescriptorSet { @@ -209,74 +209,74 @@ func (x *GetServiceDescReply) GetFileDescSet() *descriptorpb.FileDescriptorSet { return nil } -var File_metadata_proto protoreflect.FileDescriptor +var File_metadata_metadata_proto protoreflect.FileDescriptor -var file_metadata_proto_rawDesc = []byte{ - 0x0a, 0x0e, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x12, 0x0a, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x1a, 0x20, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x15, 0x0a, 0x13, - 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x22, 0x49, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x18, - 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x22, 0x2b, - 0x0a, 0x15, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x73, 0x63, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x5d, 0x0a, 0x13, 0x47, - 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x73, 0x63, 0x52, 0x65, 0x70, - 0x6c, 0x79, 0x12, 0x46, 0x0a, 0x0d, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x5f, - 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x6c, 0x65, - 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x53, 0x65, 0x74, 0x52, 0x0b, 0x66, - 0x69, 0x6c, 0x65, 0x44, 0x65, 0x73, 0x63, 0x53, 0x65, 0x74, 0x32, 0xdd, 0x01, 0x0a, 0x08, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x61, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1f, 0x2e, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, - 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6b, 0x72, 0x61, 0x74, 0x6f, - 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x11, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0b, 0x12, - 0x09, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x6e, 0x0a, 0x0e, 0x47, 0x65, - 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x73, 0x63, 0x12, 0x21, 0x2e, 0x6b, - 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x73, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1f, 0x2e, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x73, 0x63, 0x52, 0x65, 0x70, 0x6c, 0x79, - 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x42, 0x63, 0x0a, 0x15, 0x63, 0x6f, - 0x6d, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2e, - 0x61, 0x70, 0x69, 0x50, 0x01, 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x67, 0x6f, 0x2d, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2f, 0x6b, 0x72, 0x61, 0x74, - 0x6f, 0x73, 0x2f, 0x76, 0x32, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, - 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2f, 0x61, 0x70, 0x69, 0x3b, 0x6d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0xa2, 0x02, 0x09, 0x4b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x41, 0x50, 0x49, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +var file_metadata_metadata_proto_rawDesc = []byte{ + 0x0a, 0x17, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2f, 0x6d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a, 0x6b, 0x72, 0x61, 0x74, 0x6f, + 0x73, 0x2e, 0x61, 0x70, 0x69, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, + 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, + 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x15, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x49, 0x0a, 0x11, + 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, + 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x18, 0x0a, + 0x07, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, + 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x22, 0x2b, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x73, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x5d, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x44, 0x65, 0x73, 0x63, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x46, 0x0a, 0x0d, 0x66, + 0x69, 0x6c, 0x65, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x5f, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x6f, 0x72, 0x53, 0x65, 0x74, 0x52, 0x0b, 0x66, 0x69, 0x6c, 0x65, 0x44, 0x65, 0x73, 0x63, + 0x53, 0x65, 0x74, 0x32, 0xdd, 0x01, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x12, 0x61, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, + 0x12, 0x1f, 0x2e, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1d, 0x2e, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, + 0x22, 0x11, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0b, 0x12, 0x09, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x73, 0x12, 0x6e, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x44, 0x65, 0x73, 0x63, 0x12, 0x21, 0x2e, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x73, + 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6b, 0x72, 0x61, 0x74, 0x6f, + 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x44, 0x65, 0x73, 0x63, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x12, 0x12, 0x10, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x6e, 0x61, + 0x6d, 0x65, 0x7d, 0x42, 0x63, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x50, 0x01, 0x5a, 0x3c, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2d, 0x6b, 0x72, + 0x61, 0x74, 0x6f, 0x73, 0x2f, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2f, 0x76, 0x32, 0x2f, 0x61, + 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2f, + 0x61, 0x70, 0x69, 0x3b, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xa2, 0x02, 0x09, 0x4b, + 0x72, 0x61, 0x74, 0x6f, 0x73, 0x41, 0x50, 0x49, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( - file_metadata_proto_rawDescOnce sync.Once - file_metadata_proto_rawDescData = file_metadata_proto_rawDesc + file_metadata_metadata_proto_rawDescOnce sync.Once + file_metadata_metadata_proto_rawDescData = file_metadata_metadata_proto_rawDesc ) -func file_metadata_proto_rawDescGZIP() []byte { - file_metadata_proto_rawDescOnce.Do(func() { - file_metadata_proto_rawDescData = protoimpl.X.CompressGZIP(file_metadata_proto_rawDescData) +func file_metadata_metadata_proto_rawDescGZIP() []byte { + file_metadata_metadata_proto_rawDescOnce.Do(func() { + file_metadata_metadata_proto_rawDescData = protoimpl.X.CompressGZIP(file_metadata_metadata_proto_rawDescData) }) - return file_metadata_proto_rawDescData + return file_metadata_metadata_proto_rawDescData } -var file_metadata_proto_msgTypes = make([]protoimpl.MessageInfo, 4) -var file_metadata_proto_goTypes = []interface{}{ +var file_metadata_metadata_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_metadata_metadata_proto_goTypes = []interface{}{ (*ListServicesRequest)(nil), // 0: kratos.api.ListServicesRequest (*ListServicesReply)(nil), // 1: kratos.api.ListServicesReply (*GetServiceDescRequest)(nil), // 2: kratos.api.GetServiceDescRequest (*GetServiceDescReply)(nil), // 3: kratos.api.GetServiceDescReply (*descriptorpb.FileDescriptorSet)(nil), // 4: google.protobuf.FileDescriptorSet } -var file_metadata_proto_depIdxs = []int32{ +var file_metadata_metadata_proto_depIdxs = []int32{ 4, // 0: kratos.api.GetServiceDescReply.file_desc_set:type_name -> google.protobuf.FileDescriptorSet 0, // 1: kratos.api.Metadata.ListServices:input_type -> kratos.api.ListServicesRequest 2, // 2: kratos.api.Metadata.GetServiceDesc:input_type -> kratos.api.GetServiceDescRequest @@ -289,13 +289,13 @@ var file_metadata_proto_depIdxs = []int32{ 0, // [0:1] is the sub-list for field type_name } -func init() { file_metadata_proto_init() } -func file_metadata_proto_init() { - if File_metadata_proto != nil { +func init() { file_metadata_metadata_proto_init() } +func file_metadata_metadata_proto_init() { + if File_metadata_metadata_proto != nil { return } if !protoimpl.UnsafeEnabled { - file_metadata_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_metadata_metadata_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ListServicesRequest); i { case 0: return &v.state @@ -307,7 +307,7 @@ func file_metadata_proto_init() { return nil } } - file_metadata_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_metadata_metadata_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ListServicesReply); i { case 0: return &v.state @@ -319,7 +319,7 @@ func file_metadata_proto_init() { return nil } } - file_metadata_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_metadata_metadata_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetServiceDescRequest); i { case 0: return &v.state @@ -331,7 +331,7 @@ func file_metadata_proto_init() { return nil } } - file_metadata_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_metadata_metadata_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GetServiceDescReply); i { case 0: return &v.state @@ -348,18 +348,18 @@ func file_metadata_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_metadata_proto_rawDesc, + RawDescriptor: file_metadata_metadata_proto_rawDesc, NumEnums: 0, NumMessages: 4, NumExtensions: 0, NumServices: 1, }, - GoTypes: file_metadata_proto_goTypes, - DependencyIndexes: file_metadata_proto_depIdxs, - MessageInfos: file_metadata_proto_msgTypes, + GoTypes: file_metadata_metadata_proto_goTypes, + DependencyIndexes: file_metadata_metadata_proto_depIdxs, + MessageInfos: file_metadata_metadata_proto_msgTypes, }.Build() - File_metadata_proto = out.File - file_metadata_proto_rawDesc = nil - file_metadata_proto_goTypes = nil - file_metadata_proto_depIdxs = nil + File_metadata_metadata_proto = out.File + file_metadata_metadata_proto_rawDesc = nil + file_metadata_metadata_proto_goTypes = nil + file_metadata_metadata_proto_depIdxs = nil } diff --git a/api/metadata/metadata_grpc.pb.go b/api/metadata/metadata_grpc.pb.go index c110fe06f..eeafa0357 100644 --- a/api/metadata/metadata_grpc.pb.go +++ b/api/metadata/metadata_grpc.pb.go @@ -137,5 +137,5 @@ var Metadata_ServiceDesc = grpc.ServiceDesc{ }, }, Streams: []grpc.StreamDesc{}, - Metadata: "metadata.proto", + Metadata: "metadata/metadata.proto", } diff --git a/api/metadata/metadata_http.pb.go b/api/metadata/metadata_http.pb.go index d4f6f3d1a..c610aa2c6 100644 --- a/api/metadata/metadata_http.pb.go +++ b/api/metadata/metadata_http.pb.go @@ -26,11 +26,102 @@ type MetadataHandler interface { } func NewMetadataHandler(srv MetadataHandler, opts ...http1.HandleOption) http.Handler { + h := http1.DefaultHandleOptions() + for _, o := range opts { + o(&h) + } r := mux.NewRouter() - r.Handle("/services", http1.NewHandler(srv.ListServices, opts...)).Methods("GET") + r.HandleFunc("/services", func(w http.ResponseWriter, r *http.Request) { + var in ListServicesRequest + if err := h.Decode(r, &in); err != nil { + h.Error(w, r, err) + return + } - r.Handle("/services/{name}", http1.NewHandler(srv.GetServiceDesc, opts...)).Methods("GET") + next := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.ListServices(ctx, req.(*ListServicesRequest)) + } + if h.Middleware != nil { + next = h.Middleware(next) + } + out, err := next(r.Context(), &in) + if err != nil { + h.Error(w, r, err) + return + } + reply := out.(*ListServicesReply) + if err := h.Encode(w, r, reply); err != nil { + h.Error(w, r, err) + } + }).Methods("GET") + + r.HandleFunc("/services/{name}", func(w http.ResponseWriter, r *http.Request) { + var in GetServiceDescRequest + if err := h.Decode(r, &in); err != nil { + h.Error(w, r, err) + return + } + + if err := binding.BindVars(mux.Vars(r), &in); err != nil { + h.Error(w, r, err) + return + } + + next := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.GetServiceDesc(ctx, req.(*GetServiceDescRequest)) + } + if h.Middleware != nil { + next = h.Middleware(next) + } + out, err := next(r.Context(), &in) + if err != nil { + h.Error(w, r, err) + return + } + reply := out.(*GetServiceDescReply) + if err := h.Encode(w, r, reply); err != nil { + h.Error(w, r, err) + } + }).Methods("GET") return r } + +type MetadataHttpClient interface { + GetServiceDesc(ctx context.Context, req *GetServiceDescRequest, opts ...http1.CallOption) (rsp *GetServiceDescReply, err error) + + ListServices(ctx context.Context, req *ListServicesRequest, opts ...http1.CallOption) (rsp *ListServicesReply, err error) +} + +type MetadataHttpClientImpl struct { + cc *http1.Client +} + +func NewMetadataHttpClient(client *http1.Client) MetadataHttpClient { + return &MetadataHttpClientImpl{client} +} + +func (c *MetadataHttpClientImpl) GetServiceDesc(ctx context.Context, in *GetServiceDescRequest, opts ...http1.CallOption) (out *GetServiceDescReply, err error) { + path := binding.EncodePath("GET", "/services/{name}", in) + out = &GetServiceDescReply{} + + err = c.cc.Invoke(ctx, path, nil, &out, http1.Method("GET"), http1.PathPattern("/services/{name}")) + + if err != nil { + return + } + return +} + +func (c *MetadataHttpClientImpl) ListServices(ctx context.Context, in *ListServicesRequest, opts ...http1.CallOption) (out *ListServicesReply, err error) { + path := binding.EncodePath("GET", "/services", in) + out = &ListServicesReply{} + + err = c.cc.Invoke(ctx, path, nil, &out, http1.Method("GET"), http1.PathPattern("/services")) + + if err != nil { + return + } + return +} diff --git a/cmd/protoc-gen-go-http/http.go b/cmd/protoc-gen-go-http/http.go index 46b87c536..1f8a63142 100644 --- a/cmd/protoc-gen-go-http/http.go +++ b/cmd/protoc-gen-go-http/http.go @@ -114,14 +114,18 @@ func buildHTTPRule(g *protogen.GeneratedFile, m *protogen.Method, rule *annotati responseBody = rule.ResponseBody md := buildMethodDesc(g, m, method, path) if body == "*" { - md.Body = "*" + md.HasBody = true + md.Body = "" } else if body != "" { - md.Body = "." + body + md.HasBody = true + md.Body = "." + camelCaseVars(body) + } else { + md.HasBody = false } if responseBody == "*" { - md.ResponseBody = "*" + md.ResponseBody = "" } else if responseBody != "" { - md.ResponseBody = "." + responseBody + md.ResponseBody = "." + camelCaseVars(responseBody) } return md } diff --git a/cmd/protoc-gen-go-http/template.go b/cmd/protoc-gen-go-http/template.go index 58553c270..d37eee4ce 100644 --- a/cmd/protoc-gen-go-http/template.go +++ b/cmd/protoc-gen-go-http/template.go @@ -14,9 +14,40 @@ type {{.ServiceType}}Handler interface { } func New{{.ServiceType}}Handler(srv {{.ServiceType}}Handler, opts ...http1.HandleOption) http.Handler { + h := http1.DefaultHandleOptions() + for _, o := range opts { + o(&h) + } r := mux.NewRouter() {{range .Methods}} - r.Handle("{{.Path}}", http1.NewHandler(srv.{{.Name}}, opts...)).Methods("{{.Method}}") + r.HandleFunc("{{.Path}}", func(w http.ResponseWriter, r *http.Request) { + var in {{.Request}} + if err := h.Decode(r, &in{{.Body}}); err != nil { + h.Error(w, r, err) + return + } + {{if ne (len .Vars) 0}} + if err := binding.BindVars(mux.Vars(r), &in); err != nil { + h.Error(w, r, err) + return + } + {{end}} + next := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.{{.Name}}(ctx, req.(*{{.Request}})) + } + if h.Middleware != nil { + next = h.Middleware(next) + } + out, err := next(r.Context(), &in) + if err != nil { + h.Error(w, r, err) + return + } + reply := out.(*{{.Reply}}) + if err := h.Encode(w, r, reply{{.ResponseBody}}); err != nil { + h.Error(w, r, err) + } + }).Methods("{{.Method}}") {{end}} return r } @@ -39,12 +70,13 @@ func New{{.ServiceType}}HttpClient (client *http1.Client) {{.ServiceType}}HttpCl {{$svrName := .ServiceName}} {{range .MethodSets}} func (c *{{$svrType}}HttpClientImpl) {{.Name}}(ctx context.Context, in *{{.Request}}, opts ...http1.CallOption) (out *{{.Reply}}, err error) { - path := "{{.Path}}" - method := "{{.Method}}" - body := "{{.Body}}" - + path := binding.EncodePath("{{.Method}}", "{{.Path}}", in) out = &{{.Reply}}{} - err = c.cc.Invoke(ctx, path, in, out, http1.BodyPattern(body), http1.Method(method)) + {{if .HasBody }} + err = c.cc.Invoke(ctx, path, in{{.Body}}, &out{{.ResponseBody}}, http1.Method("{{.Method}}"), http1.PathPattern("{{.Path}}")) + {{else}} + err = c.cc.Invoke(ctx, path, nil, &out{{.ResponseBody}}, http1.Method("{{.Method}}"), http1.PathPattern("{{.Path}}")) + {{end}} if err != nil { return } @@ -66,12 +98,12 @@ type methodDesc struct { Name string Num int Vars []string - Forms []string Request string Reply string // http_rule Path string Method string + HasBody bool Body string ResponseBody string } diff --git a/examples/helloworld/helloworld/helloworld_http.pb.go b/examples/helloworld/helloworld/helloworld_http.pb.go index 0bf9fea13..c3ec46cab 100644 --- a/examples/helloworld/helloworld/helloworld_http.pb.go +++ b/examples/helloworld/helloworld/helloworld_http.pb.go @@ -24,9 +24,40 @@ type GreeterHandler interface { } func NewGreeterHandler(srv GreeterHandler, opts ...http1.HandleOption) http.Handler { + h := http1.DefaultHandleOptions() + for _, o := range opts { + o(&h) + } r := mux.NewRouter() - r.Handle("/helloworld/{name}", http1.NewHandler(srv.SayHello, opts...)).Methods("GET") + r.HandleFunc("/helloworld/{name}", func(w http.ResponseWriter, r *http.Request) { + var in HelloRequest + if err := h.Decode(r, &in); err != nil { + h.Error(w, r, err) + return + } + + if err := binding.BindVars(mux.Vars(r), &in); err != nil { + h.Error(w, r, err) + return + } + + next := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.SayHello(ctx, req.(*HelloRequest)) + } + if h.Middleware != nil { + next = h.Middleware(next) + } + out, err := next(r.Context(), &in) + if err != nil { + h.Error(w, r, err) + return + } + reply := out.(*HelloReply) + if err := h.Encode(w, r, reply); err != nil { + h.Error(w, r, err) + } + }).Methods("GET") return r } @@ -44,12 +75,11 @@ func NewGreeterHttpClient(client *http1.Client) GreeterHttpClient { } func (c *GreeterHttpClientImpl) SayHello(ctx context.Context, in *HelloRequest, opts ...http1.CallOption) (out *HelloReply, err error) { - path := "/helloworld/{name}" - method := "GET" - body := "" - + path := binding.EncodePath("GET", "/helloworld/{name}", in) out = &HelloReply{} - err = c.cc.Invoke(ctx, path, in, out, http1.BodyPattern(body), http1.Method(method)) + + err = c.cc.Invoke(ctx, path, nil, &out, http1.Method("GET"), http1.PathPattern("/helloworld/{name}")) + if err != nil { return } diff --git a/examples/http/handler/main.go b/examples/http/handler/main.go index c65ae9e0c..53913bec0 100644 --- a/examples/http/handler/main.go +++ b/examples/http/handler/main.go @@ -34,8 +34,8 @@ func main() { users: make(map[string]*User), } router := mux.NewRouter() - router.Handle("/users", http.NewHandler(us.Add)).Methods("POST") - router.Handle("/users/{id}", http.NewHandler(us.Get)).Methods("GET") + router.Handle("/users/add", http.NewHandler(us.Add)).Methods("POST") + router.Handle("/users/detail", http.NewHandler(us.Get)).Methods("GET") httpSrv := http.NewServer(http.Address(":8000")) httpSrv.HandlePrefix("/", router) diff --git a/examples/proto/echo_service.pb.go b/examples/proto/echo_service.pb.go index f8438f709..c8e37f9c2 100644 --- a/examples/proto/echo_service.pb.go +++ b/examples/proto/echo_service.pb.go @@ -1,18 +1,17 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.25.0 -// protoc v3.13.0 +// protoc-gen-go v1.26.0 +// protoc v3.14.0 // source: echo_service.proto package testproto import ( - proto "github.com/golang/protobuf/proto" - _struct "github.com/golang/protobuf/ptypes/struct" _ "google.golang.org/genproto/googleapis/api/annotations" - field_mask "google.golang.org/genproto/protobuf/field_mask" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + fieldmaskpb "google.golang.org/protobuf/types/known/fieldmaskpb" + structpb "google.golang.org/protobuf/types/known/structpb" reflect "reflect" sync "sync" ) @@ -24,10 +23,6 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - type Corpus int32 const ( @@ -332,8 +327,8 @@ type DynamicMessage struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - StructField *_struct.Struct `protobuf:"bytes,1,opt,name=struct_field,json=structField,proto3" json:"struct_field,omitempty"` - ValueField *_struct.Value `protobuf:"bytes,2,opt,name=value_field,json=valueField,proto3" json:"value_field,omitempty"` + StructField *structpb.Struct `protobuf:"bytes,1,opt,name=struct_field,json=structField,proto3" json:"struct_field,omitempty"` + ValueField *structpb.Value `protobuf:"bytes,2,opt,name=value_field,json=valueField,proto3" json:"value_field,omitempty"` } func (x *DynamicMessage) Reset() { @@ -368,14 +363,14 @@ func (*DynamicMessage) Descriptor() ([]byte, []int) { return file_echo_service_proto_rawDescGZIP(), []int{2} } -func (x *DynamicMessage) GetStructField() *_struct.Struct { +func (x *DynamicMessage) GetStructField() *structpb.Struct { if x != nil { return x.StructField } return nil } -func (x *DynamicMessage) GetValueField() *_struct.Value { +func (x *DynamicMessage) GetValueField() *structpb.Value { if x != nil { return x.ValueField } @@ -387,8 +382,8 @@ type DynamicMessageUpdate struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Body *DynamicMessage `protobuf:"bytes,1,opt,name=body,proto3" json:"body,omitempty"` - UpdateMask *field_mask.FieldMask `protobuf:"bytes,2,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"` + Body *DynamicMessage `protobuf:"bytes,1,opt,name=body,proto3" json:"body,omitempty"` + UpdateMask *fieldmaskpb.FieldMask `protobuf:"bytes,2,opt,name=update_mask,json=updateMask,proto3" json:"update_mask,omitempty"` } func (x *DynamicMessageUpdate) Reset() { @@ -430,7 +425,7 @@ func (x *DynamicMessageUpdate) GetBody() *DynamicMessage { return nil } -func (x *DynamicMessageUpdate) GetUpdateMask() *field_mask.FieldMask { +func (x *DynamicMessageUpdate) GetUpdateMask() *fieldmaskpb.FieldMask { if x != nil { return x.UpdateMask } @@ -491,7 +486,7 @@ var file_echo_service_proto_rawDesc = []byte{ 0x4d, 0x41, 0x47, 0x45, 0x53, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x45, 0x57, 0x53, 0x10, 0x04, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x52, 0x4f, 0x44, 0x55, 0x43, 0x54, 0x53, 0x10, 0x05, 0x12, 0x09, 0x0a, 0x05, 0x56, 0x49, - 0x44, 0x45, 0x4f, 0x10, 0x06, 0x32, 0xcc, 0x05, 0x0a, 0x0b, 0x45, 0x63, 0x68, 0x6f, 0x53, 0x65, + 0x44, 0x45, 0x4f, 0x10, 0x06, 0x32, 0xcf, 0x05, 0x0a, 0x0b, 0x45, 0x63, 0x68, 0x6f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0xf2, 0x01, 0x0a, 0x04, 0x45, 0x63, 0x68, 0x6f, 0x12, 0x18, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x18, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, @@ -513,35 +508,36 @@ var file_echo_service_proto_rawDesc = []byte{ 0x1a, 0x18, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, - 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x62, 0x6f, 0x64, 0x79, 0x3a, 0x01, 0x2a, 0x12, 0x82, 0x01, 0x0a, + 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x62, 0x6f, 0x64, 0x79, 0x3a, 0x01, 0x2a, 0x12, 0x85, 0x01, 0x0a, 0x10, 0x45, 0x63, 0x68, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x1f, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x1a, 0x1f, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x22, 0x2c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x26, 0x22, 0x1e, 0x2f, 0x76, 0x31, + 0x61, 0x74, 0x65, 0x22, 0x2f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x29, 0x22, 0x1e, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x72, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x62, 0x6f, 0x64, 0x79, 0x62, 0x04, 0x62, 0x6f, 0x64, - 0x79, 0x12, 0x6c, 0x0a, 0x0a, 0x45, 0x63, 0x68, 0x6f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, - 0x18, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x6d, 0x70, - 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x18, 0x2e, 0x74, 0x65, 0x73, 0x74, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x22, 0x2a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x24, 0x2a, 0x22, 0x2f, 0x76, 0x31, - 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x64, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x2f, 0x7b, 0x6e, 0x75, 0x6d, 0x7d, 0x12, - 0x73, 0x0a, 0x09, 0x45, 0x63, 0x68, 0x6f, 0x50, 0x61, 0x74, 0x63, 0x68, 0x12, 0x1f, 0x2e, 0x74, - 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x1a, 0x1f, 0x2e, - 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, - 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x22, 0x24, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x32, 0x16, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, - 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x70, 0x61, 0x74, 0x63, 0x68, 0x3a, 0x04, - 0x62, 0x6f, 0x64, 0x79, 0x42, 0x51, 0x5a, 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, - 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2d, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2f, 0x6b, 0x72, 0x61, - 0x74, 0x6f, 0x73, 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, - 0x65, 0x6e, 0x2d, 0x67, 0x6f, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x3b, 0x74, 0x65, - 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x62, 0x6f, 0x64, 0x79, 0x3a, 0x01, 0x2a, 0x62, 0x04, + 0x62, 0x6f, 0x64, 0x79, 0x12, 0x6c, 0x0a, 0x0a, 0x45, 0x63, 0x68, 0x6f, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x12, 0x18, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, + 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x18, 0x2e, 0x74, + 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x2a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x24, 0x2a, 0x22, + 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, + 0x5f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x2f, 0x7b, 0x6e, 0x75, + 0x6d, 0x7d, 0x12, 0x73, 0x0a, 0x09, 0x45, 0x63, 0x68, 0x6f, 0x50, 0x61, 0x74, 0x63, 0x68, 0x12, + 0x1f, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x79, 0x6e, 0x61, + 0x6d, 0x69, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x1a, 0x1f, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x79, 0x6e, + 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x32, 0x16, 0x2f, 0x76, 0x31, 0x2f, 0x65, + 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x5f, 0x70, 0x61, 0x74, 0x63, + 0x68, 0x3a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x42, 0x51, 0x5a, 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2d, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2f, + 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x67, 0x6f, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x3b, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } var ( @@ -559,14 +555,14 @@ func file_echo_service_proto_rawDescGZIP() []byte { var file_echo_service_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_echo_service_proto_msgTypes = make([]protoimpl.MessageInfo, 4) var file_echo_service_proto_goTypes = []interface{}{ - (Corpus)(0), // 0: testproto.Corpus - (*Embedded)(nil), // 1: testproto.Embedded - (*SimpleMessage)(nil), // 2: testproto.SimpleMessage - (*DynamicMessage)(nil), // 3: testproto.DynamicMessage - (*DynamicMessageUpdate)(nil), // 4: testproto.DynamicMessageUpdate - (*_struct.Struct)(nil), // 5: google.protobuf.Struct - (*_struct.Value)(nil), // 6: google.protobuf.Value - (*field_mask.FieldMask)(nil), // 7: google.protobuf.FieldMask + (Corpus)(0), // 0: testproto.Corpus + (*Embedded)(nil), // 1: testproto.Embedded + (*SimpleMessage)(nil), // 2: testproto.SimpleMessage + (*DynamicMessage)(nil), // 3: testproto.DynamicMessage + (*DynamicMessageUpdate)(nil), // 4: testproto.DynamicMessageUpdate + (*structpb.Struct)(nil), // 5: google.protobuf.Struct + (*structpb.Value)(nil), // 6: google.protobuf.Value + (*fieldmaskpb.FieldMask)(nil), // 7: google.protobuf.FieldMask } var file_echo_service_proto_depIdxs = []int32{ 1, // 0: testproto.SimpleMessage.status:type_name -> testproto.Embedded diff --git a/examples/proto/echo_service.proto b/examples/proto/echo_service.proto index a0a6b743b..ed0841563 100644 --- a/examples/proto/echo_service.proto +++ b/examples/proto/echo_service.proto @@ -89,6 +89,7 @@ service EchoService { rpc EchoResponseBody(DynamicMessageUpdate) returns (DynamicMessageUpdate) { option (google.api.http) = { post: "/v1/example/echo_response_body" + body: "*" response_body: "body" }; } diff --git a/examples/proto/echo_service_http.pb.go b/examples/proto/echo_service_http.pb.go index 438314f3a..5ee31378a 100644 --- a/examples/proto/echo_service_http.pb.go +++ b/examples/proto/echo_service_http.pb.go @@ -32,25 +32,257 @@ type EchoServiceHandler interface { } func NewEchoServiceHandler(srv EchoServiceHandler, opts ...http1.HandleOption) http.Handler { + h := http1.DefaultHandleOptions() + for _, o := range opts { + o(&h) + } r := mux.NewRouter() - r.Handle("/v1/example/echo/{id}/{num}", http1.NewHandler(srv.Echo, opts...)).Methods("GET") + r.HandleFunc("/v1/example/echo/{id}/{num}", func(w http.ResponseWriter, r *http.Request) { + var in SimpleMessage + if err := h.Decode(r, &in); err != nil { + h.Error(w, r, err) + return + } - r.Handle("/v1/example/echo/{id}/{num}/{lang}", http1.NewHandler(srv.Echo, opts...)).Methods("GET") + if err := binding.BindVars(mux.Vars(r), &in); err != nil { + h.Error(w, r, err) + return + } - r.Handle("/v1/example/echo1/{id}/{line_num}/{status.note}", http1.NewHandler(srv.Echo, opts...)).Methods("GET") + next := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.Echo(ctx, req.(*SimpleMessage)) + } + if h.Middleware != nil { + next = h.Middleware(next) + } + out, err := next(r.Context(), &in) + if err != nil { + h.Error(w, r, err) + return + } + reply := out.(*SimpleMessage) + if err := h.Encode(w, r, reply); err != nil { + h.Error(w, r, err) + } + }).Methods("GET") - r.Handle("/v1/example/echo2/{no.note}", http1.NewHandler(srv.Echo, opts...)).Methods("GET") + r.HandleFunc("/v1/example/echo/{id}/{num}/{lang}", func(w http.ResponseWriter, r *http.Request) { + var in SimpleMessage + if err := h.Decode(r, &in); err != nil { + h.Error(w, r, err) + return + } - r.Handle("/v1/example/echo/{id}", http1.NewHandler(srv.Echo, opts...)).Methods("POST") + if err := binding.BindVars(mux.Vars(r), &in); err != nil { + h.Error(w, r, err) + return + } - r.Handle("/v1/example/echo_body", http1.NewHandler(srv.EchoBody, opts...)).Methods("POST") + next := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.Echo(ctx, req.(*SimpleMessage)) + } + if h.Middleware != nil { + next = h.Middleware(next) + } + out, err := next(r.Context(), &in) + if err != nil { + h.Error(w, r, err) + return + } + reply := out.(*SimpleMessage) + if err := h.Encode(w, r, reply); err != nil { + h.Error(w, r, err) + } + }).Methods("GET") - r.Handle("/v1/example/echo_response_body", http1.NewHandler(srv.EchoResponseBody, opts...)).Methods("POST") + r.HandleFunc("/v1/example/echo1/{id}/{line_num}/{status.note}", func(w http.ResponseWriter, r *http.Request) { + var in SimpleMessage + if err := h.Decode(r, &in); err != nil { + h.Error(w, r, err) + return + } - r.Handle("/v1/example/echo_delete/{id}/{num}", http1.NewHandler(srv.EchoDelete, opts...)).Methods("DELETE") + if err := binding.BindVars(mux.Vars(r), &in); err != nil { + h.Error(w, r, err) + return + } - r.Handle("/v1/example/echo_patch", http1.NewHandler(srv.EchoPatch, opts...)).Methods("PATCH") + next := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.Echo(ctx, req.(*SimpleMessage)) + } + if h.Middleware != nil { + next = h.Middleware(next) + } + out, err := next(r.Context(), &in) + if err != nil { + h.Error(w, r, err) + return + } + reply := out.(*SimpleMessage) + if err := h.Encode(w, r, reply); err != nil { + h.Error(w, r, err) + } + }).Methods("GET") + + r.HandleFunc("/v1/example/echo2/{no.note}", func(w http.ResponseWriter, r *http.Request) { + var in SimpleMessage + if err := h.Decode(r, &in); err != nil { + h.Error(w, r, err) + return + } + + if err := binding.BindVars(mux.Vars(r), &in); err != nil { + h.Error(w, r, err) + return + } + + next := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.Echo(ctx, req.(*SimpleMessage)) + } + if h.Middleware != nil { + next = h.Middleware(next) + } + out, err := next(r.Context(), &in) + if err != nil { + h.Error(w, r, err) + return + } + reply := out.(*SimpleMessage) + if err := h.Encode(w, r, reply); err != nil { + h.Error(w, r, err) + } + }).Methods("GET") + + r.HandleFunc("/v1/example/echo/{id}", func(w http.ResponseWriter, r *http.Request) { + var in SimpleMessage + if err := h.Decode(r, &in); err != nil { + h.Error(w, r, err) + return + } + + if err := binding.BindVars(mux.Vars(r), &in); err != nil { + h.Error(w, r, err) + return + } + + next := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.Echo(ctx, req.(*SimpleMessage)) + } + if h.Middleware != nil { + next = h.Middleware(next) + } + out, err := next(r.Context(), &in) + if err != nil { + h.Error(w, r, err) + return + } + reply := out.(*SimpleMessage) + if err := h.Encode(w, r, reply); err != nil { + h.Error(w, r, err) + } + }).Methods("POST") + + r.HandleFunc("/v1/example/echo_body", func(w http.ResponseWriter, r *http.Request) { + var in SimpleMessage + if err := h.Decode(r, &in); err != nil { + h.Error(w, r, err) + return + } + + next := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.EchoBody(ctx, req.(*SimpleMessage)) + } + if h.Middleware != nil { + next = h.Middleware(next) + } + out, err := next(r.Context(), &in) + if err != nil { + h.Error(w, r, err) + return + } + reply := out.(*SimpleMessage) + if err := h.Encode(w, r, reply); err != nil { + h.Error(w, r, err) + } + }).Methods("POST") + + r.HandleFunc("/v1/example/echo_response_body", func(w http.ResponseWriter, r *http.Request) { + var in DynamicMessageUpdate + if err := h.Decode(r, &in); err != nil { + h.Error(w, r, err) + return + } + + next := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.EchoResponseBody(ctx, req.(*DynamicMessageUpdate)) + } + if h.Middleware != nil { + next = h.Middleware(next) + } + out, err := next(r.Context(), &in) + if err != nil { + h.Error(w, r, err) + return + } + reply := out.(*DynamicMessageUpdate) + if err := h.Encode(w, r, reply.Body); err != nil { + h.Error(w, r, err) + } + }).Methods("POST") + + r.HandleFunc("/v1/example/echo_delete/{id}/{num}", func(w http.ResponseWriter, r *http.Request) { + var in SimpleMessage + if err := h.Decode(r, &in); err != nil { + h.Error(w, r, err) + return + } + + if err := binding.BindVars(mux.Vars(r), &in); err != nil { + h.Error(w, r, err) + return + } + + next := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.EchoDelete(ctx, req.(*SimpleMessage)) + } + if h.Middleware != nil { + next = h.Middleware(next) + } + out, err := next(r.Context(), &in) + if err != nil { + h.Error(w, r, err) + return + } + reply := out.(*SimpleMessage) + if err := h.Encode(w, r, reply); err != nil { + h.Error(w, r, err) + } + }).Methods("DELETE") + + r.HandleFunc("/v1/example/echo_patch", func(w http.ResponseWriter, r *http.Request) { + var in DynamicMessageUpdate + if err := h.Decode(r, &in.Body); err != nil { + h.Error(w, r, err) + return + } + + next := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.EchoPatch(ctx, req.(*DynamicMessageUpdate)) + } + if h.Middleware != nil { + next = h.Middleware(next) + } + out, err := next(r.Context(), &in) + if err != nil { + h.Error(w, r, err) + return + } + reply := out.(*DynamicMessageUpdate) + if err := h.Encode(w, r, reply); err != nil { + h.Error(w, r, err) + } + }).Methods("PATCH") return r } @@ -76,12 +308,11 @@ func NewEchoServiceHttpClient(client *http1.Client) EchoServiceHttpClient { } func (c *EchoServiceHttpClientImpl) Echo(ctx context.Context, in *SimpleMessage, opts ...http1.CallOption) (out *SimpleMessage, err error) { - path := "/v1/example/echo/{id}" - method := "POST" - body := "" - + path := binding.EncodePath("POST", "/v1/example/echo/{id}", in) out = &SimpleMessage{} - err = c.cc.Invoke(ctx, path, in, out, http1.BodyPattern(body), http1.Method(method)) + + err = c.cc.Invoke(ctx, path, nil, &out, http1.Method("POST"), http1.PathPattern("/v1/example/echo/{id}")) + if err != nil { return } @@ -89,12 +320,11 @@ func (c *EchoServiceHttpClientImpl) Echo(ctx context.Context, in *SimpleMessage, } func (c *EchoServiceHttpClientImpl) EchoBody(ctx context.Context, in *SimpleMessage, opts ...http1.CallOption) (out *SimpleMessage, err error) { - path := "/v1/example/echo_body" - method := "POST" - body := "*" - + path := binding.EncodePath("POST", "/v1/example/echo_body", in) out = &SimpleMessage{} - err = c.cc.Invoke(ctx, path, in, out, http1.BodyPattern(body), http1.Method(method)) + + err = c.cc.Invoke(ctx, path, in, &out, http1.Method("POST"), http1.PathPattern("/v1/example/echo_body")) + if err != nil { return } @@ -102,12 +332,11 @@ func (c *EchoServiceHttpClientImpl) EchoBody(ctx context.Context, in *SimpleMess } func (c *EchoServiceHttpClientImpl) EchoDelete(ctx context.Context, in *SimpleMessage, opts ...http1.CallOption) (out *SimpleMessage, err error) { - path := "/v1/example/echo_delete/{id}/{num}" - method := "DELETE" - body := "" - + path := binding.EncodePath("DELETE", "/v1/example/echo_delete/{id}/{num}", in) out = &SimpleMessage{} - err = c.cc.Invoke(ctx, path, in, out, http1.BodyPattern(body), http1.Method(method)) + + err = c.cc.Invoke(ctx, path, nil, &out, http1.Method("DELETE"), http1.PathPattern("/v1/example/echo_delete/{id}/{num}")) + if err != nil { return } @@ -115,12 +344,11 @@ func (c *EchoServiceHttpClientImpl) EchoDelete(ctx context.Context, in *SimpleMe } func (c *EchoServiceHttpClientImpl) EchoPatch(ctx context.Context, in *DynamicMessageUpdate, opts ...http1.CallOption) (out *DynamicMessageUpdate, err error) { - path := "/v1/example/echo_patch" - method := "PATCH" - body := ".body" - + path := binding.EncodePath("PATCH", "/v1/example/echo_patch", in) out = &DynamicMessageUpdate{} - err = c.cc.Invoke(ctx, path, in, out, http1.BodyPattern(body), http1.Method(method)) + + err = c.cc.Invoke(ctx, path, in.Body, &out, http1.Method("PATCH"), http1.PathPattern("/v1/example/echo_patch")) + if err != nil { return } @@ -128,12 +356,11 @@ func (c *EchoServiceHttpClientImpl) EchoPatch(ctx context.Context, in *DynamicMe } func (c *EchoServiceHttpClientImpl) EchoResponseBody(ctx context.Context, in *DynamicMessageUpdate, opts ...http1.CallOption) (out *DynamicMessageUpdate, err error) { - path := "/v1/example/echo_response_body" - method := "POST" - body := "" - + path := binding.EncodePath("POST", "/v1/example/echo_response_body", in) out = &DynamicMessageUpdate{} - err = c.cc.Invoke(ctx, path, in, out, http1.BodyPattern(body), http1.Method(method)) + + err = c.cc.Invoke(ctx, path, in, &out.Body, http1.Method("POST"), http1.PathPattern("/v1/example/echo_response_body")) + if err != nil { return } diff --git a/examples/proto/echo_service_test.go b/examples/proto/echo_service_test.go index e6ccfbae9..555867fb2 100644 --- a/examples/proto/echo_service_test.go +++ b/examples/proto/echo_service_test.go @@ -119,17 +119,20 @@ func testEchoClient(t *testing.T, addr string) { }} dout *DynamicMessageUpdate ) - if dout, err = cli.EchoPatch(context.Background(), din); err != nil { - t.Fatal(err) - } - if din.Body.ValueField.GetStringValue() != dout.Body.ValueField.GetStringValue() { - t.Errorf("EchoPatch expected %s got %s", din, dout) - } if dout, err = cli.EchoResponseBody(context.Background(), din); err != nil { t.Fatal(err) } if din.Body.ValueField.GetStringValue() != dout.Body.ValueField.GetStringValue() { - t.Errorf("EchoResponseBody expected %s got %s", din, dout) + t.Fatalf("EchoResponseBody expected %s got %s", din, dout) + } + if dout, err = cli.EchoPatch(context.Background(), din); err != nil { + t.Fatal(err) + } + if dout.Body == nil { + panic("dout.body is nil") + } + if din.Body.ValueField.GetStringValue() != dout.Body.ValueField.GetStringValue() { + t.Fatalf("EchoPatch expected %s got %s", din, dout) } } diff --git a/examples/proto/stream.pb.go b/examples/proto/stream.pb.go index a2fed91d8..04d555905 100644 --- a/examples/proto/stream.pb.go +++ b/examples/proto/stream.pb.go @@ -1,18 +1,17 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.25.0 -// protoc v3.13.0 +// protoc-gen-go v1.26.0 +// protoc v3.14.0 // source: stream.proto package testproto import ( - proto "github.com/golang/protobuf/proto" - empty "github.com/golang/protobuf/ptypes/empty" _ "google.golang.org/genproto/googleapis/api/annotations" httpbody "google.golang.org/genproto/googleapis/api/httpbody" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + emptypb "google.golang.org/protobuf/types/known/emptypb" reflect "reflect" ) @@ -23,10 +22,6 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - var File_stream_proto protoreflect.FileDescriptor var file_stream_proto_rawDesc = []byte{ @@ -53,7 +48,7 @@ var file_stream_proto_rawDesc = []byte{ } var file_stream_proto_goTypes = []interface{}{ - (*empty.Empty)(nil), // 0: google.protobuf.Empty + (*emptypb.Empty)(nil), // 0: google.protobuf.Empty (*httpbody.HttpBody)(nil), // 1: google.api.HttpBody } var file_stream_proto_depIdxs = []int32{ diff --git a/examples/proto/stream_grpc.pb.go b/examples/proto/stream_grpc.pb.go index ed744d6bd..9dfe96f83 100644 --- a/examples/proto/stream_grpc.pb.go +++ b/examples/proto/stream_grpc.pb.go @@ -4,11 +4,11 @@ package testproto import ( context "context" - empty "github.com/golang/protobuf/ptypes/empty" httpbody "google.golang.org/genproto/googleapis/api/httpbody" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" + emptypb "google.golang.org/protobuf/types/known/emptypb" ) // This is a compile-time assertion to ensure that this generated file @@ -20,7 +20,7 @@ const _ = grpc.SupportPackageIsVersion7 // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type StreamServiceClient interface { - Download(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (StreamService_DownloadClient, error) + Download(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (StreamService_DownloadClient, error) } type streamServiceClient struct { @@ -31,7 +31,7 @@ func NewStreamServiceClient(cc grpc.ClientConnInterface) StreamServiceClient { return &streamServiceClient{cc} } -func (c *streamServiceClient) Download(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (StreamService_DownloadClient, error) { +func (c *streamServiceClient) Download(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (StreamService_DownloadClient, error) { stream, err := c.cc.NewStream(ctx, &StreamService_ServiceDesc.Streams[0], "/testproto.StreamService/Download", opts...) if err != nil { return nil, err @@ -67,7 +67,7 @@ func (x *streamServiceDownloadClient) Recv() (*httpbody.HttpBody, error) { // All implementations must embed UnimplementedStreamServiceServer // for forward compatibility type StreamServiceServer interface { - Download(*empty.Empty, StreamService_DownloadServer) error + Download(*emptypb.Empty, StreamService_DownloadServer) error mustEmbedUnimplementedStreamServiceServer() } @@ -75,7 +75,7 @@ type StreamServiceServer interface { type UnimplementedStreamServiceServer struct { } -func (UnimplementedStreamServiceServer) Download(*empty.Empty, StreamService_DownloadServer) error { +func (UnimplementedStreamServiceServer) Download(*emptypb.Empty, StreamService_DownloadServer) error { return status.Errorf(codes.Unimplemented, "method Download not implemented") } func (UnimplementedStreamServiceServer) mustEmbedUnimplementedStreamServiceServer() {} @@ -92,7 +92,7 @@ func RegisterStreamServiceServer(s grpc.ServiceRegistrar, srv StreamServiceServe } func _StreamService_Download_Handler(srv interface{}, stream grpc.ServerStream) error { - m := new(empty.Empty) + m := new(emptypb.Empty) if err := stream.RecvMsg(m); err != nil { return err } diff --git a/examples/proto/stream_http.pb.go b/examples/proto/stream_http.pb.go index 4ca8e97fc..c1b3e3351 100644 --- a/examples/proto/stream_http.pb.go +++ b/examples/proto/stream_http.pb.go @@ -23,6 +23,10 @@ type StreamServiceHandler interface { } func NewStreamServiceHandler(srv StreamServiceHandler, opts ...http1.HandleOption) http.Handler { + h := http1.DefaultHandleOptions() + for _, o := range opts { + o(&h) + } r := mux.NewRouter() return r diff --git a/transport/http/binding/encode.go b/transport/http/binding/encode.go new file mode 100644 index 000000000..5aa86b36d --- /dev/null +++ b/transport/http/binding/encode.go @@ -0,0 +1,231 @@ +package binding + +import ( + "encoding/base64" + "fmt" + "net/url" + "reflect" + "regexp" + "strconv" + "strings" + "time" + + "google.golang.org/genproto/protobuf/field_mask" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/types/known/durationpb" + "google.golang.org/protobuf/types/known/timestamppb" + "google.golang.org/protobuf/types/known/wrapperspb" +) + +// EncodePath binds proto message to url path +func EncodePath(method string, pathPattern string, msg proto.Message) string { + if msg == nil || (reflect.ValueOf(msg).Kind() == reflect.Ptr && reflect.ValueOf(msg).IsNil()) { + return pathPattern + } + reg := regexp.MustCompile(`/{[.\w]+}`) + if reg == nil { + return pathPattern + } + pathParams := make(map[string]struct{}, 0) + path := reg.ReplaceAllStringFunc(pathPattern, func(in string) string { + if len(in) < 4 { + return in + } + key := in[2 : len(in)-1] + vars := strings.Split(key, ".") + if value, err := getValueByField(msg.ProtoReflect(), vars); err == nil { + pathParams[key] = struct{}{} + return "/" + value + } + return in + }) + if method == "GET" { + u, err := encodeQuery(msg) + if err == nil && len(u) > 0 { + for key := range pathParams { + delete(u, key) + } + query := u.Encode() + if query != "" { + path += "?" + query + } + } + } + + return path +} + +func getValueByField(v protoreflect.Message, fieldPath []string) (string, error) { + var fd protoreflect.FieldDescriptor + for i, fieldName := range fieldPath { + fields := v.Descriptor().Fields() + if fd = fields.ByName(protoreflect.Name(fieldName)); fd == nil { + fd = fields.ByJSONName(fieldName) + if fd == nil { + return "", fmt.Errorf("field path not found: %q", fieldName) + } + } + if i == len(fieldPath)-1 { + break + } + if fd.Message() == nil || fd.Cardinality() == protoreflect.Repeated { + return "", fmt.Errorf("invalid path: %q is not a message", fieldName) + } + v = v.Get(fd).Message() + } + return encodeField(fd, v.Get(fd)) +} + +func encodeQuery(msg proto.Message) (url.Values, error) { + if msg == nil || (reflect.ValueOf(msg).Kind() == reflect.Ptr && reflect.ValueOf(msg).IsNil()) { + return url.Values{}, nil + } + u := make(url.Values) + err := encodeByField(u, "", msg.ProtoReflect()) + if err != nil { + return nil, err + } + return u, nil +} + +func encodeByField(u url.Values, path string, v protoreflect.Message) error { + for i := 0; i < v.Descriptor().Fields().Len(); i++ { + fd := v.Descriptor().Fields().Get(i) + var key string = fd.TextName() + var newPath string + if path == "" { + newPath = key + } else { + newPath = path + "." + key + } + if fd.HasJSONName() { + key = fd.JSONName() + } + switch { + case fd.IsList(): + list, err := encodeRepeatedField(fd, v.Get(fd).List()) + if err != nil { + return err + } + u[newPath] = list + case fd.IsMap(): + m, err := encodeMapField(fd, v.Get(fd).Map()) + if err != nil { + return err + } + for k, value := range m { + u[fmt.Sprintf("%s[%s]", newPath, k)] = []string{value} + } + case (fd.Kind() == protoreflect.MessageKind) || (fd.Kind() == protoreflect.GroupKind): + value, err := encodeMessage(fd.Message(), v.Get(fd)) + if err == nil { + u[newPath] = []string{value} + return nil + } + return encodeByField(u, newPath, v.Get(fd).Message()) + default: + value, err := encodeField(fd, v.Get(fd)) + if err != nil { + return err + } + u[newPath] = []string{value} + } + } + return nil +} + +func encodeMessageField(fieldDescriptor protoreflect.FieldDescriptor, msgValue protoreflect.Message) (string, error) { + return encodeField(fieldDescriptor, msgValue.Get(fieldDescriptor)) +} + +func encodeRepeatedField(fieldDescriptor protoreflect.FieldDescriptor, list protoreflect.List) ([]string, error) { + var values []string + for i := 0; i < list.Len(); i++ { + value, err := encodeField(fieldDescriptor, list.Get(i)) + if err != nil { + return nil, err + } + values = append(values, value) + } + + return values, nil +} + +func encodeMapField(fieldDescriptor protoreflect.FieldDescriptor, mp protoreflect.Map) (map[string]string, error) { + m := make(map[string]string) + mp.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool { + key, err := encodeField(fieldDescriptor.MapValue(), k.Value()) + if err != nil { + return false + } + value, err := encodeField(fieldDescriptor.MapValue(), v) + if err != nil { + return false + } + m[key] = value + return true + }) + + return m, nil +} + +func encodeField(fieldDescriptor protoreflect.FieldDescriptor, value protoreflect.Value) (string, error) { + switch fieldDescriptor.Kind() { + case protoreflect.BoolKind: + return strconv.FormatBool(value.Bool()), nil + case protoreflect.EnumKind: + if fieldDescriptor.Enum().FullName() == "google.protobuf.NullValue" { + return "null", nil + } + desc := fieldDescriptor.Enum().Values().ByNumber(value.Enum()) + return string(desc.Name()), nil + case protoreflect.StringKind: + return value.String(), nil + case protoreflect.BytesKind: + return base64.URLEncoding.EncodeToString(value.Bytes()), nil + case protoreflect.MessageKind, protoreflect.GroupKind: + return encodeMessage(fieldDescriptor.Message(), value) + default: + return fmt.Sprintf("%v", value.Interface()), nil + } +} + +// marshalMessage marshals the fields in the given protoreflect.Message. +// If the typeURL is non-empty, then a synthetic "@type" field is injected +// containing the URL as the value. +func encodeMessage(msgDescriptor protoreflect.MessageDescriptor, value protoreflect.Value) (string, error) { + switch msgDescriptor.FullName() { + case "google.protobuf.Timestamp": + t, ok := value.Interface().(*timestamppb.Timestamp) + if !ok { + return "", nil + } + return t.AsTime().Format(time.RFC3339Nano), nil + case "google.protobuf.Duration": + d, ok := value.Interface().(*durationpb.Duration) + if !ok { + return "", nil + } + return d.AsDuration().String(), nil + case "google.protobuf.BytesValue": + b, ok := value.Interface().(*wrapperspb.BytesValue) + if !ok { + return "", nil + } + return base64.StdEncoding.EncodeToString(b.Value), nil + case "google.protobuf.DoubleValue", "google.protobuf.FloatValue", "google.protobuf.Int64Value", "google.protobuf.Int32Value", + "google.protobuf.UInt64Value", "google.protobuf.UInt32Value", "google.protobuf.BoolValue", "google.protobuf.StringValue": + fd := msgDescriptor.Fields() + v := value.Message().Get(fd.ByName(protoreflect.Name("value"))).Message() + return fmt.Sprintf("%v", v.Interface()), nil + case "google.protobuf.FieldMask": + m, ok := value.Interface().(*field_mask.FieldMask) + if !ok { + return "", nil + } + return strings.Join(m.Paths, ","), nil + default: + return "", fmt.Errorf("unsupported message type: %q", string(msgDescriptor.FullName())) + } +} diff --git a/transport/http/binding/proto.go b/transport/http/binding/proto.go index 27512147e..a56d693c5 100644 --- a/transport/http/binding/proto.go +++ b/transport/http/binding/proto.go @@ -4,7 +4,6 @@ import ( "encoding/base64" "errors" "fmt" - "regexp" "strconv" "strings" "time" @@ -18,46 +17,6 @@ import ( "google.golang.org/protobuf/types/known/wrapperspb" ) -// ProtoPath binds proto message to url path -func ProtoPath(template string, msg proto.Message) string { - reg := regexp.MustCompile(`/{[.\w]+}`) - if reg == nil { - return template - } - return reg.ReplaceAllStringFunc(template, func(in string) string { - if len(in) < 4 { - return in - } - str := in[2 : len(in)-1] - vars := strings.Split(str, ".") - if value, err := getValueByField(msg.ProtoReflect(), vars); err == nil { - return "/" + value - } - return in - }) -} - -func getValueByField(v protoreflect.Message, fieldPath []string) (string, error) { - var fd protoreflect.FieldDescriptor - for i, fieldName := range fieldPath { - fields := v.Descriptor().Fields() - if fd = fields.ByName(protoreflect.Name(fieldName)); fd == nil { - fd = fields.ByJSONName(fieldName) - if fd == nil { - return "", fmt.Errorf("field path not found: %q", fieldName) - } - } - if i == len(fieldPath)-1 { - break - } - if fd.Message() == nil || fd.Cardinality() == protoreflect.Repeated { - return "", fmt.Errorf("invalid path: %q is not a message", fieldName) - } - v = v.Mutable(fd).Message() - } - return fmt.Sprintf("%v", v.Get(fd).Interface()), nil -} - // MapProto sets a value in a nested Protobuf structure. // Deprecated: use BindValue instead. func MapProto(msg proto.Message, values map[string]string) error { diff --git a/transport/http/binding/proto_test.go b/transport/http/binding/proto_test.go index 944d0214f..6a828b23e 100644 --- a/transport/http/binding/proto_test.go +++ b/transport/http/binding/proto_test.go @@ -6,25 +6,25 @@ import ( ) func TestProtoPath(t *testing.T) { - url := ProtoPath("http://helloworld.Greeter/helloworld/{name}/sub/{sub.name}", &HelloRequest{Name: "test", Sub: &Sub{Name: "2233!!!"}}) + url := EncodePath("POST", "http://helloworld.Greeter/helloworld/{name}/sub/{sub.name}", &HelloRequest{Name: "test", Sub: &Sub{Name: "2233!!!"}}) fmt.Println(url) if url != `http://helloworld.Greeter/helloworld/test/sub/2233!!!` { t.Fatalf("proto path not expected!actual: %s ", url) } - url = ProtoPath("http://helloworld.Greeter/helloworld/sub", &HelloRequest{Name: "test", Sub: &Sub{Name: "2233!!!"}}) + url = EncodePath("POST", "http://helloworld.Greeter/helloworld/sub", &HelloRequest{Name: "test", Sub: &Sub{Name: "2233!!!"}}) fmt.Println(url) if url != `http://helloworld.Greeter/helloworld/sub` { t.Fatalf("proto path not expected!actual: %s ", url) } - url = ProtoPath("http://helloworld.Greeter/helloworld/{name}/sub/{sub.name}", &HelloRequest{Name: "test"}) + url = EncodePath("POST", "http://helloworld.Greeter/helloworld/{name}/sub/{sub.name}", &HelloRequest{Name: "test"}) fmt.Println(url) if url != `http://helloworld.Greeter/helloworld/test/sub/` { t.Fatalf("proto path not expected!actual: %s ", url) } - url = ProtoPath("http://helloworld.Greeter/helloworld/{name}/sub/{sub.name33}", &HelloRequest{Name: "test"}) + url = EncodePath("POST", "http://helloworld.Greeter/helloworld/{name}/sub/{sub.name33}", &HelloRequest{Name: "test"}) fmt.Println(url) if url != `http://helloworld.Greeter/helloworld/test/sub/{sub.name33}` { t.Fatalf("proto path not expected!actual: %s ", url) diff --git a/transport/http/calloption.go b/transport/http/calloption.go index 2920ead68..b794859bc 100644 --- a/transport/http/calloption.go +++ b/transport/http/calloption.go @@ -12,6 +12,11 @@ type CallOption interface { after(*callInfo, *csAttempt) } +type callInfo struct { + pathPattern string + method string +} + // EmptyCallOption does not alter the Call configuration. // It can be embedded in another structure to carry satellite data for use // by interceptors. @@ -20,28 +25,23 @@ type EmptyCallOption struct{} func (EmptyCallOption) before(*callInfo) error { return nil } func (EmptyCallOption) after(*callInfo, *csAttempt) {} -type callInfo struct { - bodyPattern string - method string -} - type csAttempt struct{} -// BodyPattern is bodyPattern -func BodyPattern(bodyPattern string) CallOption { - return BodyPatternCallOption{BodyPattern: bodyPattern} +// PathPattern is pathpattern +func PathPattern(pathPattern string) CallOption { + return PathPatternCallOption{PathPattern: pathPattern} } -// BodyPatternCallOption is BodyPattern -type BodyPatternCallOption struct { - BodyPattern string +// PathPatternCallOption is BodyPattern +type PathPatternCallOption struct { + EmptyCallOption + PathPattern string } -func (o BodyPatternCallOption) before(c *callInfo) error { - c.bodyPattern = o.BodyPattern +func (o PathPatternCallOption) before(c *callInfo) error { + c.pathPattern = o.PathPattern return nil } -func (o BodyPatternCallOption) after(c *callInfo, attempt *csAttempt) {} // Method is Method func Method(method string) CallOption { @@ -50,6 +50,7 @@ func Method(method string) CallOption { // MethodCallOption is BodyCallOption type MethodCallOption struct { + EmptyCallOption Method string } @@ -57,11 +58,9 @@ func (o MethodCallOption) before(c *callInfo) error { c.method = o.Method return nil } -func (o MethodCallOption) after(c *callInfo, attempt *csAttempt) {} func defaultCallInfo() callInfo { return callInfo{ - bodyPattern: "*", - method: "POST", + method: "POST", } } diff --git a/transport/http/client.go b/transport/http/client.go index 80525690b..3ef20e58c 100644 --- a/transport/http/client.go +++ b/transport/http/client.go @@ -14,8 +14,6 @@ import ( "github.com/go-kratos/kratos/v2/internal/httputil" "github.com/go-kratos/kratos/v2/middleware" "github.com/go-kratos/kratos/v2/transport" - "github.com/go-kratos/kratos/v2/transport/http/binding" - "google.golang.org/protobuf/proto" ) // Client is http client @@ -147,7 +145,7 @@ func NewClient(ctx context.Context, opts ...ClientOption) (*Client, error) { } // Invoke makes an rpc call procedure for remote service. -func (client *Client) Invoke(ctx context.Context, pathPattern string, args interface{}, reply interface{}, opts ...CallOption) error { +func (client *Client) Invoke(ctx context.Context, path string, args interface{}, reply interface{}, opts ...CallOption) error { var ( reqBody io.Reader contentType string @@ -160,14 +158,7 @@ func (client *Client) Invoke(ctx context.Context, pathPattern string, args inter } } - path := pathPattern if args != nil { - // TODO: support for struct path bindings - path = binding.ProtoPath(path, args.(proto.Message)) - } - url := fmt.Sprintf("%s://%s%s", client.schema, client.endpoint, path) - if args != nil && c.bodyPattern != "" { - // TODO: only encode the target field of args var ( body []byte err error @@ -178,20 +169,21 @@ func (client *Client) Invoke(ctx context.Context, pathPattern string, args inter } reqBody = bytes.NewReader(body) } + url := fmt.Sprintf("%s://%s%s", client.schema, client.endpoint, path) req, err := http.NewRequest(c.method, url, reqBody) if err != nil { return err } - if client.userAgent != "" { - req.Header.Set("User-Agent", client.userAgent) - } if contentType != "" { req.Header.Set("Content-Type", contentType) } + if client.userAgent != "" { + req.Header.Set("User-Agent", client.userAgent) + } ctx = transport.NewContext(ctx, transport.Transport{Kind: transport.KindHTTP}) ctx = NewClientContext(ctx, ClientInfo{ - PathPattern: pathPattern, + PathPattern: c.pathPattern, Request: req, }) diff --git a/transport/http/handle.go b/transport/http/handle.go index e843240f8..21972edde 100644 --- a/transport/http/handle.go +++ b/transport/http/handle.go @@ -13,7 +13,6 @@ import ( "github.com/go-kratos/kratos/v2/middleware" "github.com/go-kratos/kratos/v2/middleware/recovery" "github.com/go-kratos/kratos/v2/transport/http/binding" - "github.com/gorilla/mux" ) // SupportPackageIsVersion1 These constants should not be referenced from any other code. @@ -167,9 +166,6 @@ func defaultRequestDecoder(req *http.Request, v interface{}) error { return errors.BadRequest("CODEC", err.Error()) } } - if err := binding.BindVars(mux.Vars(req), v); err != nil { - return errors.BadRequest("CODEC", err.Error()) - } return nil }