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/client.go b/go/client.go index 62baa41..c02efe7 100644 --- a/go/client.go +++ b/go/client.go @@ -48,9 +48,32 @@ 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) { + // 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: + // following prints the error desc, "Your name contains 14 characters, ..." + 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 a0922cf..4846299 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 fileDescriptor0, []int{1} } +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) +} + +var xxx_messageInfo_HelloResp proto.InternalMessageInfo func (m *HelloResp) GetResult() string { if m != nil { @@ -68,9 +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{ + // 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, 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. @@ -81,8 +173,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! @@ -90,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 { @@ -102,7 +197,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 +206,23 @@ 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 +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 // SayHello('Euler') -> Hello, Euler! @@ -127,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) { @@ -169,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), @@ -181,23 +304,11 @@ var _HelloService_serviceDesc = grpc.ServiceDesc{ MethodName: "SayHelloStrict", Handler: _HelloService_SayHelloStrict_Handler, }, + { + MethodName: "SayHelloAdvanced", + Handler: _HelloService_SayHelloAdvanced_Handler, + }, }, 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, -} diff --git a/go/server.go b/go/server.go index 45762ed..959c783 100644 --- a/go/server.go +++ b/go/server.go @@ -28,6 +28,24 @@ 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. + 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 + // 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 +} + func Serve() { addr := fmt.Sprintf(":%d", 50051) conn, err := net.Listen("tcp", addr) 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 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/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) 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 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))