From 9fdbed5d3f45865f0b08e45706d035b59307ba38 Mon Sep 17 00:00:00 2001 From: avi Date: Thu, 14 May 2020 16:56:49 +0530 Subject: [PATCH 1/8] update instructions for pb gen --- go/README.md | 5 ++ go/hello/hello.pb.go | 136 +++++++++++++++++++++++++++---------------- 2 files changed, 90 insertions(+), 51 deletions(-) diff --git a/go/README.md b/go/README.md index 24d653e..eb9c852 100644 --- a/go/README.md +++ b/go/README.md @@ -2,6 +2,11 @@ ## Instructions +Install the go protobuf plugin required: + + $ go get github.com/golang/protobuf/protoc-gen-go + $ go install github.com/golang/protobuf/protoc-gen-go + Generate protobuf files: $ protoc -I ../ ../hello.proto --go_out=plugins=grpc:./hello diff --git a/go/hello/hello.pb.go b/go/hello/hello.pb.go index a0922cf..c7d5746 100644 --- a/go/hello/hello.pb.go +++ b/go/hello/hello.pb.go @@ -1,28 +1,16 @@ -// Code generated by protoc-gen-go. +// Code generated by protoc-gen-go. DO NOT EDIT. // source: hello.proto -// DO NOT EDIT! -/* -Package hello is a generated protocol buffer package. +// for Golang -for Golang - -It is generated from these files: - hello.proto - -It has these top-level messages: - HelloReq - HelloResp -*/ package hello -import proto "github.com/golang/protobuf/proto" -import fmt "fmt" -import math "math" - import ( - context "golang.org/x/net/context" + context "context" + fmt "fmt" + proto "github.com/golang/protobuf/proto" grpc "google.golang.org/grpc" + math "math" ) // Reference imports to suppress errors if they are not otherwise used. @@ -34,16 +22,39 @@ var _ = math.Inf // is compatible with the proto package it is being compiled against. // A compilation error at this line likely means your copy of the // proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package type HelloReq struct { - Name string `protobuf:"bytes,1,opt,name=Name" json:"Name,omitempty"` + Name string `protobuf:"bytes,1,opt,name=Name,proto3" json:"Name,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *HelloReq) Reset() { *m = HelloReq{} } +func (m *HelloReq) String() string { return proto.CompactTextString(m) } +func (*HelloReq) ProtoMessage() {} +func (*HelloReq) Descriptor() ([]byte, []int) { + return fileDescriptor_61ef911816e0a8ce, []int{0} +} + +func (m *HelloReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_HelloReq.Unmarshal(m, b) +} +func (m *HelloReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_HelloReq.Marshal(b, m, deterministic) +} +func (m *HelloReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_HelloReq.Merge(m, src) +} +func (m *HelloReq) XXX_Size() int { + return xxx_messageInfo_HelloReq.Size(m) +} +func (m *HelloReq) XXX_DiscardUnknown() { + xxx_messageInfo_HelloReq.DiscardUnknown(m) } -func (m *HelloReq) Reset() { *m = HelloReq{} } -func (m *HelloReq) String() string { return proto.CompactTextString(m) } -func (*HelloReq) ProtoMessage() {} -func (*HelloReq) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } +var xxx_messageInfo_HelloReq proto.InternalMessageInfo func (m *HelloReq) GetName() string { if m != nil { @@ -53,13 +64,36 @@ func (m *HelloReq) GetName() string { } type HelloResp struct { - Result string `protobuf:"bytes,1,opt,name=Result" json:"Result,omitempty"` + Result string `protobuf:"bytes,1,opt,name=Result,proto3" json:"Result,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *HelloResp) Reset() { *m = HelloResp{} } +func (m *HelloResp) String() string { return proto.CompactTextString(m) } +func (*HelloResp) ProtoMessage() {} +func (*HelloResp) Descriptor() ([]byte, []int) { + return fileDescriptor_61ef911816e0a8ce, []int{1} +} + +func (m *HelloResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_HelloResp.Unmarshal(m, b) +} +func (m *HelloResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_HelloResp.Marshal(b, m, deterministic) +} +func (m *HelloResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_HelloResp.Merge(m, src) +} +func (m *HelloResp) XXX_Size() int { + return xxx_messageInfo_HelloResp.Size(m) +} +func (m *HelloResp) XXX_DiscardUnknown() { + xxx_messageInfo_HelloResp.DiscardUnknown(m) } -func (m *HelloResp) Reset() { *m = HelloResp{} } -func (m *HelloResp) String() string { return proto.CompactTextString(m) } -func (*HelloResp) ProtoMessage() {} -func (*HelloResp) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } +var xxx_messageInfo_HelloResp proto.InternalMessageInfo func (m *HelloResp) GetResult() string { if m != nil { @@ -73,6 +107,22 @@ func init() { proto.RegisterType((*HelloResp)(nil), "hello.HelloResp") } +func init() { proto.RegisterFile("hello.proto", fileDescriptor_61ef911816e0a8ce) } + +var fileDescriptor_61ef911816e0a8ce = []byte{ + // 146 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0xce, 0x48, 0xcd, 0xc9, + 0xc9, 0xd7, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x05, 0x73, 0x94, 0xe4, 0xb8, 0x38, 0x3c, + 0x40, 0x8c, 0xa0, 0xd4, 0x42, 0x21, 0x21, 0x2e, 0x16, 0xbf, 0xc4, 0xdc, 0x54, 0x09, 0x46, 0x05, + 0x46, 0x0d, 0xce, 0x20, 0x30, 0x5b, 0x49, 0x99, 0x8b, 0x13, 0x2a, 0x5f, 0x5c, 0x20, 0x24, 0xc6, + 0xc5, 0x16, 0x94, 0x5a, 0x5c, 0x9a, 0x53, 0x02, 0x55, 0x02, 0xe5, 0x19, 0x95, 0x71, 0xf1, 0x80, + 0x15, 0x05, 0xa7, 0x16, 0x95, 0x65, 0x26, 0xa7, 0x0a, 0xe9, 0x73, 0x71, 0x04, 0x27, 0x56, 0x82, + 0x85, 0x84, 0xf8, 0xf5, 0x20, 0xb6, 0xc2, 0x6c, 0x91, 0x12, 0x40, 0x15, 0x28, 0x2e, 0x50, 0x62, + 0x10, 0x32, 0xe5, 0xe2, 0x83, 0x69, 0x08, 0x2e, 0x29, 0xca, 0x4c, 0x2e, 0x21, 0x4a, 0x5b, 0x12, + 0x1b, 0xd8, 0x2b, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xd3, 0x08, 0xc5, 0xac, 0xd9, 0x00, + 0x00, 0x00, +} + // Reference imports to suppress errors if they are not otherwise used. var _ context.Context var _ grpc.ClientConn @@ -81,8 +131,9 @@ var _ grpc.ClientConn // is compatible with the grpc package it is being compiled against. const _ = grpc.SupportPackageIsVersion4 -// Client API for HelloService service - +// HelloServiceClient is the client API for HelloService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type HelloServiceClient interface { // This thing just says Hello to anyone // SayHello('Euler') -> Hello, Euler! @@ -102,7 +153,7 @@ func NewHelloServiceClient(cc *grpc.ClientConn) HelloServiceClient { func (c *helloServiceClient) SayHello(ctx context.Context, in *HelloReq, opts ...grpc.CallOption) (*HelloResp, error) { out := new(HelloResp) - err := grpc.Invoke(ctx, "/hello.HelloService/SayHello", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/hello.HelloService/SayHello", in, out, opts...) if err != nil { return nil, err } @@ -111,15 +162,14 @@ func (c *helloServiceClient) SayHello(ctx context.Context, in *HelloReq, opts .. func (c *helloServiceClient) SayHelloStrict(ctx context.Context, in *HelloReq, opts ...grpc.CallOption) (*HelloResp, error) { out := new(HelloResp) - err := grpc.Invoke(ctx, "/hello.HelloService/SayHelloStrict", in, out, c.cc, opts...) + err := c.cc.Invoke(ctx, "/hello.HelloService/SayHelloStrict", in, out, opts...) if err != nil { return nil, err } return out, nil } -// Server API for HelloService service - +// HelloServiceServer is the server API for HelloService service. type HelloServiceServer interface { // This thing just says Hello to anyone // SayHello('Euler') -> Hello, Euler! @@ -185,19 +235,3 @@ var _HelloService_serviceDesc = grpc.ServiceDesc{ Streams: []grpc.StreamDesc{}, Metadata: "hello.proto", } - -func init() { proto.RegisterFile("hello.proto", fileDescriptor0) } - -var fileDescriptor0 = []byte{ - // 146 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xe2, 0xce, 0x48, 0xcd, 0xc9, - 0xc9, 0xd7, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x05, 0x73, 0x94, 0xe4, 0xb8, 0x38, 0x3c, - 0x40, 0x8c, 0xa0, 0xd4, 0x42, 0x21, 0x21, 0x2e, 0x16, 0xbf, 0xc4, 0xdc, 0x54, 0x09, 0x46, 0x05, - 0x46, 0x0d, 0xce, 0x20, 0x30, 0x5b, 0x49, 0x99, 0x8b, 0x13, 0x2a, 0x5f, 0x5c, 0x20, 0x24, 0xc6, - 0xc5, 0x16, 0x94, 0x5a, 0x5c, 0x9a, 0x53, 0x02, 0x55, 0x02, 0xe5, 0x19, 0x95, 0x71, 0xf1, 0x80, - 0x15, 0x05, 0xa7, 0x16, 0x95, 0x65, 0x26, 0xa7, 0x0a, 0xe9, 0x73, 0x71, 0x04, 0x27, 0x56, 0x82, - 0x85, 0x84, 0xf8, 0xf5, 0x20, 0xb6, 0xc2, 0x6c, 0x91, 0x12, 0x40, 0x15, 0x28, 0x2e, 0x50, 0x62, - 0x10, 0x32, 0xe5, 0xe2, 0x83, 0x69, 0x08, 0x2e, 0x29, 0xca, 0x4c, 0x2e, 0x21, 0x4a, 0x5b, 0x12, - 0x1b, 0xd8, 0x2b, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xd3, 0x08, 0xc5, 0xac, 0xd9, 0x00, - 0x00, 0x00, -} From 479727c000ce83bec520055d40f58326e0017fdd Mon Sep 17 00:00:00 2001 From: avi Date: Thu, 14 May 2020 17:57:53 +0530 Subject: [PATCH 2/8] update proto to include Error msg --- hello.proto | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hello.proto b/hello.proto index 86b78c8..ecf8546 100644 --- a/hello.proto +++ b/hello.proto @@ -9,6 +9,8 @@ service HelloService { // Strict Version responds only to requests which have `Name` length // less than 10 characters rpc SayHelloStrict(HelloReq) returns (HelloResp) {}; + // Same like previous one, but returns an advanced error, an instance of Error message defined below + rpc SayHelloAdvanced(HelloReq) returns (HelloResp) {}; } message HelloReq { @@ -17,4 +19,8 @@ message HelloReq { message HelloResp { string Result = 1; +} + +message Error { + string Description = 1; } \ No newline at end of file From aba0bf1117c533344c0cc5050c0135fad585a06c Mon Sep 17 00:00:00 2001 From: avi Date: Thu, 14 May 2020 17:58:13 +0530 Subject: [PATCH 3/8] Add support for advanced erorrs --- go/client.go | 24 +++++++++++- go/hello/hello.pb.go | 91 ++++++++++++++++++++++++++++++++++++++++---- go/server.go | 16 ++++++++ 3 files changed, 123 insertions(+), 8 deletions(-) diff --git a/go/client.go b/go/client.go index 62baa41..a3f854d 100644 --- a/go/client.go +++ b/go/client.go @@ -48,9 +48,31 @@ func main() { // Want to take specific action based on specific error? if codes.InvalidArgument == errStatus.Code() { // do your stuff here - log.Fatal() } } + resp, err = c.SayHelloAdvanced( + context.Background(), + &api.HelloReq{Name: "Leonhard Euler"}, + ) + + if err != nil { + // this is advanced error handling. Everything works exactly like the previous example, but in this one you also + // get extra error information + errStatus, _ := status.FromError(err) + fmt.Println(errStatus.Message()) + // lets print the error code which is `INVALID_ARGUMENT` + fmt.Println(errStatus.Code()) + // now lets get the advanced error info! + for _, d := range errStatus.Details() { + switch errProto := d.(type) { + case *api.Error: + // this will print the error desc + fmt.Println(errProto.Description) + default: + log.Fatal("Unexpected type: ", errProto) + } + } + } fmt.Println(resp.GetResult()) } diff --git a/go/hello/hello.pb.go b/go/hello/hello.pb.go index c7d5746..4846299 100644 --- a/go/hello/hello.pb.go +++ b/go/hello/hello.pb.go @@ -102,25 +102,67 @@ func (m *HelloResp) GetResult() string { return "" } +type Error struct { + Description string `protobuf:"bytes,1,opt,name=Description,proto3" json:"Description,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Error) Reset() { *m = Error{} } +func (m *Error) String() string { return proto.CompactTextString(m) } +func (*Error) ProtoMessage() {} +func (*Error) Descriptor() ([]byte, []int) { + return fileDescriptor_61ef911816e0a8ce, []int{2} +} + +func (m *Error) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Error.Unmarshal(m, b) +} +func (m *Error) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Error.Marshal(b, m, deterministic) +} +func (m *Error) XXX_Merge(src proto.Message) { + xxx_messageInfo_Error.Merge(m, src) +} +func (m *Error) XXX_Size() int { + return xxx_messageInfo_Error.Size(m) +} +func (m *Error) XXX_DiscardUnknown() { + xxx_messageInfo_Error.DiscardUnknown(m) +} + +var xxx_messageInfo_Error proto.InternalMessageInfo + +func (m *Error) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + func init() { proto.RegisterType((*HelloReq)(nil), "hello.HelloReq") proto.RegisterType((*HelloResp)(nil), "hello.HelloResp") + proto.RegisterType((*Error)(nil), "hello.Error") } func init() { proto.RegisterFile("hello.proto", fileDescriptor_61ef911816e0a8ce) } var fileDescriptor_61ef911816e0a8ce = []byte{ - // 146 bytes of a gzipped FileDescriptorProto + // 191 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0xce, 0x48, 0xcd, 0xc9, 0xc9, 0xd7, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x05, 0x73, 0x94, 0xe4, 0xb8, 0x38, 0x3c, 0x40, 0x8c, 0xa0, 0xd4, 0x42, 0x21, 0x21, 0x2e, 0x16, 0xbf, 0xc4, 0xdc, 0x54, 0x09, 0x46, 0x05, 0x46, 0x0d, 0xce, 0x20, 0x30, 0x5b, 0x49, 0x99, 0x8b, 0x13, 0x2a, 0x5f, 0x5c, 0x20, 0x24, 0xc6, - 0xc5, 0x16, 0x94, 0x5a, 0x5c, 0x9a, 0x53, 0x02, 0x55, 0x02, 0xe5, 0x19, 0x95, 0x71, 0xf1, 0x80, - 0x15, 0x05, 0xa7, 0x16, 0x95, 0x65, 0x26, 0xa7, 0x0a, 0xe9, 0x73, 0x71, 0x04, 0x27, 0x56, 0x82, - 0x85, 0x84, 0xf8, 0xf5, 0x20, 0xb6, 0xc2, 0x6c, 0x91, 0x12, 0x40, 0x15, 0x28, 0x2e, 0x50, 0x62, - 0x10, 0x32, 0xe5, 0xe2, 0x83, 0x69, 0x08, 0x2e, 0x29, 0xca, 0x4c, 0x2e, 0x21, 0x4a, 0x5b, 0x12, - 0x1b, 0xd8, 0x2b, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xd3, 0x08, 0xc5, 0xac, 0xd9, 0x00, - 0x00, 0x00, + 0xc5, 0x16, 0x94, 0x5a, 0x5c, 0x9a, 0x53, 0x02, 0x55, 0x02, 0xe5, 0x29, 0x69, 0x72, 0xb1, 0xba, + 0x16, 0x15, 0xe5, 0x17, 0x09, 0x29, 0x70, 0x71, 0xbb, 0xa4, 0x16, 0x27, 0x17, 0x65, 0x16, 0x94, + 0x64, 0xe6, 0xe7, 0x41, 0x55, 0x21, 0x0b, 0x19, 0xad, 0x67, 0xe4, 0xe2, 0x01, 0x1b, 0x18, 0x9c, + 0x5a, 0x54, 0x96, 0x99, 0x9c, 0x2a, 0xa4, 0xcf, 0xc5, 0x11, 0x9c, 0x58, 0x09, 0x16, 0x12, 0xe2, + 0xd7, 0x83, 0xb8, 0x10, 0xe6, 0x22, 0x29, 0x01, 0x54, 0x81, 0xe2, 0x02, 0x25, 0x06, 0x21, 0x53, + 0x2e, 0x3e, 0x98, 0x86, 0xe0, 0x92, 0xa2, 0xcc, 0xe4, 0x12, 0xe2, 0xb4, 0x99, 0x73, 0x09, 0xc0, + 0xb4, 0x39, 0xa6, 0x94, 0x25, 0xe6, 0x25, 0xa7, 0xa6, 0x10, 0xa5, 0x31, 0x89, 0x0d, 0x1c, 0x5e, + 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x33, 0xcd, 0xf6, 0xb9, 0x3e, 0x01, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -141,6 +183,8 @@ type HelloServiceClient interface { // Strict Version responds only to requests which have `Name` length // less than 10 characters SayHelloStrict(ctx context.Context, in *HelloReq, opts ...grpc.CallOption) (*HelloResp, error) + // Same like previous one, but returns an advanced error + SayHelloAdvanced(ctx context.Context, in *HelloReq, opts ...grpc.CallOption) (*HelloResp, error) } type helloServiceClient struct { @@ -169,6 +213,15 @@ func (c *helloServiceClient) SayHelloStrict(ctx context.Context, in *HelloReq, o return out, nil } +func (c *helloServiceClient) SayHelloAdvanced(ctx context.Context, in *HelloReq, opts ...grpc.CallOption) (*HelloResp, error) { + out := new(HelloResp) + err := c.cc.Invoke(ctx, "/hello.HelloService/SayHelloAdvanced", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // HelloServiceServer is the server API for HelloService service. type HelloServiceServer interface { // This thing just says Hello to anyone @@ -177,6 +230,8 @@ type HelloServiceServer interface { // Strict Version responds only to requests which have `Name` length // less than 10 characters SayHelloStrict(context.Context, *HelloReq) (*HelloResp, error) + // Same like previous one, but returns an advanced error + SayHelloAdvanced(context.Context, *HelloReq) (*HelloResp, error) } func RegisterHelloServiceServer(s *grpc.Server, srv HelloServiceServer) { @@ -219,6 +274,24 @@ func _HelloService_SayHelloStrict_Handler(srv interface{}, ctx context.Context, return interceptor(ctx, in, info, handler) } +func _HelloService_SayHelloAdvanced_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(HelloReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(HelloServiceServer).SayHelloAdvanced(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/hello.HelloService/SayHelloAdvanced", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(HelloServiceServer).SayHelloAdvanced(ctx, req.(*HelloReq)) + } + return interceptor(ctx, in, info, handler) +} + var _HelloService_serviceDesc = grpc.ServiceDesc{ ServiceName: "hello.HelloService", HandlerType: (*HelloServiceServer)(nil), @@ -231,6 +304,10 @@ var _HelloService_serviceDesc = grpc.ServiceDesc{ MethodName: "SayHelloStrict", Handler: _HelloService_SayHelloStrict_Handler, }, + { + MethodName: "SayHelloAdvanced", + Handler: _HelloService_SayHelloAdvanced_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "hello.proto", diff --git a/go/server.go b/go/server.go index 45762ed..2941cb4 100644 --- a/go/server.go +++ b/go/server.go @@ -28,6 +28,22 @@ func (s *HelloServer) SayHelloStrict(ctx context.Context, req *api.HelloReq) (*a return &api.HelloResp{Result: fmt.Sprintf("Hey, %s!", req.GetName())}, nil } +func (s *HelloServer) SayHelloAdvanced(ctx context.Context, req *api.HelloReq) (*api.HelloResp, error) { + if len(req.GetName()) >= 10 { + // with the error, you can also send any proto object as metadata. We will use the one we defined in the + // proto definition + // so create an api.Error obj and send that along with the error. + details := &api.Error{ + Description: fmt.Sprintf("Your name contains %d characters, but you cannot use more than 10 characters in this API request", len(req.Name)), + } + st := status.New(codes.InvalidArgument, "Length of `Name` cannot be more than 10 characters") + // following attaches the extra error metadata to the error + st, _ = st.WithDetails(details) + return nil, st.Err() + } + return &api.HelloResp{Result: fmt.Sprintf("Hey, %s!", req.GetName())}, nil +} + func Serve() { addr := fmt.Sprintf(":%d", 50051) conn, err := net.Listen("tcp", addr) From 0b273c67fcd94c99cd634ac627378ee9f8aee2ce Mon Sep 17 00:00:00 2001 From: avi Date: Thu, 14 May 2020 19:52:14 +0530 Subject: [PATCH 4/8] update go server to send the correct obj --- go/server.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/go/server.go b/go/server.go index 2941cb4..959c783 100644 --- a/go/server.go +++ b/go/server.go @@ -33,12 +33,14 @@ func (s *HelloServer) SayHelloAdvanced(ctx context.Context, req *api.HelloReq) ( // with the error, you can also send any proto object as metadata. We will use the one we defined in the // proto definition // so create an api.Error obj and send that along with the error. - details := &api.Error{ + detail := &api.Error{ Description: fmt.Sprintf("Your name contains %d characters, but you cannot use more than 10 characters in this API request", len(req.Name)), } st := status.New(codes.InvalidArgument, "Length of `Name` cannot be more than 10 characters") // following attaches the extra error metadata to the error - st, _ = st.WithDetails(details) + // in other languages, you may need to wrap the obj within an any.Any. Following `WithDetails` method does that + // for us + st, _ = st.WithDetails(detail) return nil, st.Err() } return &api.HelloResp{Result: fmt.Sprintf("Hey, %s!", req.GetName())}, nil From f260b4a2a8934ccea794c268d528cdfa3e5c6a9a Mon Sep 17 00:00:00 2001 From: avi Date: Thu, 14 May 2020 19:56:45 +0530 Subject: [PATCH 5/8] Add go client to handle the correct obj --- go/client.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/go/client.go b/go/client.go index a3f854d..c02efe7 100644 --- a/go/client.go +++ b/go/client.go @@ -66,8 +66,9 @@ func main() { // now lets get the advanced error info! for _, d := range errStatus.Details() { switch errProto := d.(type) { + // in some languages, you may need to unwrap the obj from an any.Any. However, Go grpc lib have done that already for us case *api.Error: - // this will print the error desc + // following prints the error desc, "Your name contains 14 characters, ..." fmt.Println(errProto.Description) default: log.Fatal("Unexpected type: ", errProto) From 99c097a6e8780effb10447fd6339d3661bd60d76 Mon Sep 17 00:00:00 2001 From: avi Date: Thu, 14 May 2020 19:57:39 +0530 Subject: [PATCH 6/8] update requirements --- python/requirements.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/python/requirements.txt b/python/requirements.txt index 2f63e45..aa8b68f 100644 --- a/python/requirements.txt +++ b/python/requirements.txt @@ -1 +1,5 @@ -grpcio-tools==1.2.0 +googleapis-common-protos==1.51.0 +grpcio==1.28.1 +grpcio-status==1.28.1 +grpcio-tools==1.28.1 +protobuf==3.11.3 \ No newline at end of file From 5f83152bdacc167c8d43a9bba2d20b09c10d2f1f Mon Sep 17 00:00:00 2001 From: avi Date: Thu, 14 May 2020 19:58:12 +0530 Subject: [PATCH 7/8] update python grpc files --- python/hello_pb2.py | 261 ++++++++++++++------------------------- python/hello_pb2_grpc.py | 162 +++++++++++++++++------- 2 files changed, 212 insertions(+), 211 deletions(-) diff --git a/python/hello_pb2.py b/python/hello_pb2.py index 6979c20..8fde5a1 100644 --- a/python/hello_pb2.py +++ b/python/hello_pb2.py @@ -1,13 +1,11 @@ +# -*- coding: utf-8 -*- # Generated by the protocol buffer compiler. DO NOT EDIT! # source: hello.proto -import sys -_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message from google.protobuf import reflection as _reflection from google.protobuf import symbol_database as _symbol_database -from google.protobuf import descriptor_pb2 # @@protoc_insertion_point(imports) _sym_db = _symbol_database.Default() @@ -19,9 +17,9 @@ name='hello.proto', package='hello', syntax='proto3', - serialized_pb=_b('\n\x0bhello.proto\x12\x05hello\"\x18\n\x08HelloReq\x12\x0c\n\x04Name\x18\x01 \x01(\t\"\x1b\n\tHelloResp\x12\x0e\n\x06Result\x18\x01 \x01(\t2v\n\x0cHelloService\x12/\n\x08SayHello\x12\x0f.hello.HelloReq\x1a\x10.hello.HelloResp\"\x00\x12\x35\n\x0eSayHelloStrict\x12\x0f.hello.HelloReq\x1a\x10.hello.HelloResp\"\x00\x62\x06proto3') + serialized_options=None, + serialized_pb=b'\n\x0bhello.proto\x12\x05hello\"\x18\n\x08HelloReq\x12\x0c\n\x04Name\x18\x01 \x01(\t\"\x1b\n\tHelloResp\x12\x0e\n\x06Result\x18\x01 \x01(\t\"\x1c\n\x05\x45rror\x12\x13\n\x0b\x44\x65scription\x18\x01 \x01(\t2\xaf\x01\n\x0cHelloService\x12/\n\x08SayHello\x12\x0f.hello.HelloReq\x1a\x10.hello.HelloResp\"\x00\x12\x35\n\x0eSayHelloStrict\x12\x0f.hello.HelloReq\x1a\x10.hello.HelloResp\"\x00\x12\x37\n\x10SayHelloAdvanced\x12\x0f.hello.HelloReq\x1a\x10.hello.HelloResp\"\x00\x62\x06proto3' ) -_sym_db.RegisterFileDescriptor(DESCRIPTOR) @@ -36,17 +34,17 @@ _descriptor.FieldDescriptor( name='Name', full_name='hello.HelloReq.Name', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -67,17 +65,17 @@ _descriptor.FieldDescriptor( name='Result', full_name='hello.HelloResp.Result', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -87,171 +85,104 @@ serialized_end=75, ) + +_ERROR = _descriptor.Descriptor( + name='Error', + full_name='hello.Error', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='Description', full_name='hello.Error.Description', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=77, + serialized_end=105, +) + DESCRIPTOR.message_types_by_name['HelloReq'] = _HELLOREQ DESCRIPTOR.message_types_by_name['HelloResp'] = _HELLORESP +DESCRIPTOR.message_types_by_name['Error'] = _ERROR +_sym_db.RegisterFileDescriptor(DESCRIPTOR) -HelloReq = _reflection.GeneratedProtocolMessageType('HelloReq', (_message.Message,), dict( - DESCRIPTOR = _HELLOREQ, - __module__ = 'hello_pb2' +HelloReq = _reflection.GeneratedProtocolMessageType('HelloReq', (_message.Message,), { + 'DESCRIPTOR' : _HELLOREQ, + '__module__' : 'hello_pb2' # @@protoc_insertion_point(class_scope:hello.HelloReq) - )) + }) _sym_db.RegisterMessage(HelloReq) -HelloResp = _reflection.GeneratedProtocolMessageType('HelloResp', (_message.Message,), dict( - DESCRIPTOR = _HELLORESP, - __module__ = 'hello_pb2' +HelloResp = _reflection.GeneratedProtocolMessageType('HelloResp', (_message.Message,), { + 'DESCRIPTOR' : _HELLORESP, + '__module__' : 'hello_pb2' # @@protoc_insertion_point(class_scope:hello.HelloResp) - )) + }) _sym_db.RegisterMessage(HelloResp) - -try: - # THESE ELEMENTS WILL BE DEPRECATED. - # Please use the generated *_pb2_grpc.py files instead. - import grpc - from grpc.framework.common import cardinality - from grpc.framework.interfaces.face import utilities as face_utilities - from grpc.beta import implementations as beta_implementations - from grpc.beta import interfaces as beta_interfaces - - - class HelloServiceStub(object): - - def __init__(self, channel): - """Constructor. - - Args: - channel: A grpc.Channel. - """ - self.SayHello = channel.unary_unary( - '/hello.HelloService/SayHello', - request_serializer=HelloReq.SerializeToString, - response_deserializer=HelloResp.FromString, - ) - self.SayHelloStrict = channel.unary_unary( - '/hello.HelloService/SayHelloStrict', - request_serializer=HelloReq.SerializeToString, - response_deserializer=HelloResp.FromString, - ) - - - class HelloServiceServicer(object): - - def SayHello(self, request, context): - """This thing just says Hello to anyone - SayHello('Euler') -> Hello, Euler! - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def SayHelloStrict(self, request, context): - """Strict Version responds only to requests which have `Name` length - less than 10 characters - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') +Error = _reflection.GeneratedProtocolMessageType('Error', (_message.Message,), { + 'DESCRIPTOR' : _ERROR, + '__module__' : 'hello_pb2' + # @@protoc_insertion_point(class_scope:hello.Error) + }) +_sym_db.RegisterMessage(Error) - def add_HelloServiceServicer_to_server(servicer, server): - rpc_method_handlers = { - 'SayHello': grpc.unary_unary_rpc_method_handler( - servicer.SayHello, - request_deserializer=HelloReq.FromString, - response_serializer=HelloResp.SerializeToString, - ), - 'SayHelloStrict': grpc.unary_unary_rpc_method_handler( - servicer.SayHelloStrict, - request_deserializer=HelloReq.FromString, - response_serializer=HelloResp.SerializeToString, - ), - } - generic_handler = grpc.method_handlers_generic_handler( - 'hello.HelloService', rpc_method_handlers) - server.add_generic_rpc_handlers((generic_handler,)) +_HELLOSERVICE = _descriptor.ServiceDescriptor( + name='HelloService', + full_name='hello.HelloService', + file=DESCRIPTOR, + index=0, + serialized_options=None, + serialized_start=108, + serialized_end=283, + methods=[ + _descriptor.MethodDescriptor( + name='SayHello', + full_name='hello.HelloService.SayHello', + index=0, + containing_service=None, + input_type=_HELLOREQ, + output_type=_HELLORESP, + serialized_options=None, + ), + _descriptor.MethodDescriptor( + name='SayHelloStrict', + full_name='hello.HelloService.SayHelloStrict', + index=1, + containing_service=None, + input_type=_HELLOREQ, + output_type=_HELLORESP, + serialized_options=None, + ), + _descriptor.MethodDescriptor( + name='SayHelloAdvanced', + full_name='hello.HelloService.SayHelloAdvanced', + index=2, + containing_service=None, + input_type=_HELLOREQ, + output_type=_HELLORESP, + serialized_options=None, + ), +]) +_sym_db.RegisterServiceDescriptor(_HELLOSERVICE) + +DESCRIPTOR.services_by_name['HelloService'] = _HELLOSERVICE - class BetaHelloServiceServicer(object): - """The Beta API is deprecated for 0.15.0 and later. - - It is recommended to use the GA API (classes and functions in this - file not marked beta) for all further purposes. This class was generated - only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0.""" - def SayHello(self, request, context): - """This thing just says Hello to anyone - SayHello('Euler') -> Hello, Euler! - """ - context.code(beta_interfaces.StatusCode.UNIMPLEMENTED) - def SayHelloStrict(self, request, context): - """Strict Version responds only to requests which have `Name` length - less than 10 characters - """ - context.code(beta_interfaces.StatusCode.UNIMPLEMENTED) - - - class BetaHelloServiceStub(object): - """The Beta API is deprecated for 0.15.0 and later. - - It is recommended to use the GA API (classes and functions in this - file not marked beta) for all further purposes. This class was generated - only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0.""" - def SayHello(self, request, timeout, metadata=None, with_call=False, protocol_options=None): - """This thing just says Hello to anyone - SayHello('Euler') -> Hello, Euler! - """ - raise NotImplementedError() - SayHello.future = None - def SayHelloStrict(self, request, timeout, metadata=None, with_call=False, protocol_options=None): - """Strict Version responds only to requests which have `Name` length - less than 10 characters - """ - raise NotImplementedError() - SayHelloStrict.future = None - - - def beta_create_HelloService_server(servicer, pool=None, pool_size=None, default_timeout=None, maximum_timeout=None): - """The Beta API is deprecated for 0.15.0 and later. - - It is recommended to use the GA API (classes and functions in this - file not marked beta) for all further purposes. This function was - generated only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0""" - request_deserializers = { - ('hello.HelloService', 'SayHello'): HelloReq.FromString, - ('hello.HelloService', 'SayHelloStrict'): HelloReq.FromString, - } - response_serializers = { - ('hello.HelloService', 'SayHello'): HelloResp.SerializeToString, - ('hello.HelloService', 'SayHelloStrict'): HelloResp.SerializeToString, - } - method_implementations = { - ('hello.HelloService', 'SayHello'): face_utilities.unary_unary_inline(servicer.SayHello), - ('hello.HelloService', 'SayHelloStrict'): face_utilities.unary_unary_inline(servicer.SayHelloStrict), - } - server_options = beta_implementations.server_options(request_deserializers=request_deserializers, response_serializers=response_serializers, thread_pool=pool, thread_pool_size=pool_size, default_timeout=default_timeout, maximum_timeout=maximum_timeout) - return beta_implementations.server(method_implementations, options=server_options) - - - def beta_create_HelloService_stub(channel, host=None, metadata_transformer=None, pool=None, pool_size=None): - """The Beta API is deprecated for 0.15.0 and later. - - It is recommended to use the GA API (classes and functions in this - file not marked beta) for all further purposes. This function was - generated only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0""" - request_serializers = { - ('hello.HelloService', 'SayHello'): HelloReq.SerializeToString, - ('hello.HelloService', 'SayHelloStrict'): HelloReq.SerializeToString, - } - response_deserializers = { - ('hello.HelloService', 'SayHello'): HelloResp.FromString, - ('hello.HelloService', 'SayHelloStrict'): HelloResp.FromString, - } - cardinalities = { - 'SayHello': cardinality.Cardinality.UNARY_UNARY, - 'SayHelloStrict': cardinality.Cardinality.UNARY_UNARY, - } - stub_options = beta_implementations.stub_options(host=host, metadata_transformer=metadata_transformer, request_serializers=request_serializers, response_deserializers=response_deserializers, thread_pool=pool, thread_pool_size=pool_size) - return beta_implementations.dynamic_stub(channel, 'hello.HelloService', cardinalities, options=stub_options) -except ImportError: - pass # @@protoc_insertion_point(module_scope) diff --git a/python/hello_pb2_grpc.py b/python/hello_pb2_grpc.py index 2e4a2e0..b1694e0 100644 --- a/python/hello_pb2_grpc.py +++ b/python/hello_pb2_grpc.py @@ -1,63 +1,133 @@ # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! import grpc -from grpc.framework.common import cardinality -from grpc.framework.interfaces.face import utilities as face_utilities import hello_pb2 as hello__pb2 class HelloServiceStub(object): + """Missing associated documentation comment in .proto file""" - def __init__(self, channel): - """Constructor. + def __init__(self, channel): + """Constructor. - Args: - channel: A grpc.Channel. - """ - self.SayHello = channel.unary_unary( - '/hello.HelloService/SayHello', - request_serializer=hello__pb2.HelloReq.SerializeToString, - response_deserializer=hello__pb2.HelloResp.FromString, - ) - self.SayHelloStrict = channel.unary_unary( - '/hello.HelloService/SayHelloStrict', - request_serializer=hello__pb2.HelloReq.SerializeToString, - response_deserializer=hello__pb2.HelloResp.FromString, - ) + Args: + channel: A grpc.Channel. + """ + self.SayHello = channel.unary_unary( + '/hello.HelloService/SayHello', + request_serializer=hello__pb2.HelloReq.SerializeToString, + response_deserializer=hello__pb2.HelloResp.FromString, + ) + self.SayHelloStrict = channel.unary_unary( + '/hello.HelloService/SayHelloStrict', + request_serializer=hello__pb2.HelloReq.SerializeToString, + response_deserializer=hello__pb2.HelloResp.FromString, + ) + self.SayHelloAdvanced = channel.unary_unary( + '/hello.HelloService/SayHelloAdvanced', + request_serializer=hello__pb2.HelloReq.SerializeToString, + response_deserializer=hello__pb2.HelloResp.FromString, + ) class HelloServiceServicer(object): + """Missing associated documentation comment in .proto file""" - def SayHello(self, request, context): - """This thing just says Hello to anyone - SayHello('Euler') -> Hello, Euler! - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') + def SayHello(self, request, context): + """This thing just says Hello to anyone + SayHello('Euler') -> Hello, Euler! + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') - def SayHelloStrict(self, request, context): - """Strict Version responds only to requests which have `Name` length - less than 10 characters - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') + def SayHelloStrict(self, request, context): + """Strict Version responds only to requests which have `Name` length + less than 10 characters + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def SayHelloAdvanced(self, request, context): + """Same like previous one, but returns an advanced error, an instance of Error message defined below + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') def add_HelloServiceServicer_to_server(servicer, server): - rpc_method_handlers = { - 'SayHello': grpc.unary_unary_rpc_method_handler( - servicer.SayHello, - request_deserializer=hello__pb2.HelloReq.FromString, - response_serializer=hello__pb2.HelloResp.SerializeToString, - ), - 'SayHelloStrict': grpc.unary_unary_rpc_method_handler( - servicer.SayHelloStrict, - request_deserializer=hello__pb2.HelloReq.FromString, - response_serializer=hello__pb2.HelloResp.SerializeToString, - ), - } - generic_handler = grpc.method_handlers_generic_handler( - 'hello.HelloService', rpc_method_handlers) - server.add_generic_rpc_handlers((generic_handler,)) + rpc_method_handlers = { + 'SayHello': grpc.unary_unary_rpc_method_handler( + servicer.SayHello, + request_deserializer=hello__pb2.HelloReq.FromString, + response_serializer=hello__pb2.HelloResp.SerializeToString, + ), + 'SayHelloStrict': grpc.unary_unary_rpc_method_handler( + servicer.SayHelloStrict, + request_deserializer=hello__pb2.HelloReq.FromString, + response_serializer=hello__pb2.HelloResp.SerializeToString, + ), + 'SayHelloAdvanced': grpc.unary_unary_rpc_method_handler( + servicer.SayHelloAdvanced, + request_deserializer=hello__pb2.HelloReq.FromString, + response_serializer=hello__pb2.HelloResp.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'hello.HelloService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + + + # This class is part of an EXPERIMENTAL API. +class HelloService(object): + """Missing associated documentation comment in .proto file""" + + @staticmethod + def SayHello(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/hello.HelloService/SayHello', + hello__pb2.HelloReq.SerializeToString, + hello__pb2.HelloResp.FromString, + options, channel_credentials, + call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def SayHelloStrict(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/hello.HelloService/SayHelloStrict', + hello__pb2.HelloReq.SerializeToString, + hello__pb2.HelloResp.FromString, + options, channel_credentials, + call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def SayHelloAdvanced(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/hello.HelloService/SayHelloAdvanced', + hello__pb2.HelloReq.SerializeToString, + hello__pb2.HelloResp.FromString, + options, channel_credentials, + call_credentials, compression, wait_for_ready, timeout, metadata) From 919a4c770929f8eb7d0db56de3feedebec65056e Mon Sep 17 00:00:00 2001 From: avi Date: Thu, 14 May 2020 20:20:45 +0530 Subject: [PATCH 8/8] add python client and server for rich error --- python/client.py | 25 +++++++++++++++++++++++++ python/server.py | 22 ++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/python/client.py b/python/client.py index 0663445..15da0e2 100644 --- a/python/client.py +++ b/python/client.py @@ -1,4 +1,6 @@ import grpc +from grpc_status import rpc_status +from google.rpc import error_details_pb2 import hello_pb2 import hello_pb2_grpc @@ -33,6 +35,29 @@ def run(): else: print(response.Result) + try: + response = stub.SayHelloAdvanced(hello_pb2.HelloReq( + Name='Leonhard Euler')) + except grpc.RpcError as e: + # this is advanced error handling. Everything works exactly like the previous example, but in this one you also + # get extra error information + print(e.details()) + status_code = e.code() + # should print `INVALID_ARGUMENT` + print(status_code.name) + # now lets get the advanced error info! + status = rpc_status.from_call(e) + for detail in status.details: + if detail.Is(hello_pb2.Error.DESCRIPTOR): + err_proto = hello_pb2.Error() + detail.Unpack(err_proto) + # following prints the error desc, "Your name contains 14 characters, ..." + print(err_proto.Description) + else: + raise RuntimeError('Unexpected type: %s' % detail) + else: + print(response.Result) + if __name__ == '__main__': run() diff --git a/python/server.py b/python/server.py index 0cd8206..102eb9a 100644 --- a/python/server.py +++ b/python/server.py @@ -2,6 +2,9 @@ from concurrent import futures import grpc +from google.rpc import status_pb2, code_pb2 +from google.protobuf import any_pb2 +from grpc_status import rpc_status import hello_pb2 import hello_pb2_grpc @@ -23,6 +26,25 @@ def SayHelloStrict(self, request, context): return hello_pb2.HelloResp(Result="Hey, {}!".format(request.Name)) + def SayHelloAdvanced(self, request, context): + if len(request.Name) >= 10: + # with the error, you can also send any proto object as metadata. We will use the one we defined in the + # proto definition + # so create an api.Error obj and send that along with the error. + desc = F"Your name contains {len(request.Name)} characters, but you cannot use more than 10 characters in this API request" + my_err = hello_pb2.Error(Description=desc) + # we need to wrap our obj in any.Any object + detail = any_pb2.Any() + detail.Pack(my_err) + err_status = status_pb2.Status( + code=code_pb2.INVALID_ARGUMENT, + message='Length of `Name` cannot be more than 10 characters', + details=[detail], + ) + context.abort_with_status(rpc_status.to_status(err_status)) + return hello_pb2.HelloResp() + + return hello_pb2.HelloResp(Result="Hey, {}!".format(request.Name)) def serve(): server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))