Raising a server error to the client with grpc

FunkySayu picture FunkySayu · Dec 6, 2016 · Viewed 12k times · Source

Let's consider a simple service:

service Something {
    rpc Do(Request) returns Response;
}

message Request {
    string field = 1;
}

message Response {
    string response = 1; 
}

Assume I have to do some checking on the Request.field, I want to raise a client error if the field is invalid:

class MyService(proto_pb2.SomethingServicer):

    def Do(self, request, context):
        if not is_valid_field(request.field):
            raise ValueError("Damn!")  # Or something like that
        return proto_pb2.Response(response="Yeah!")

With the following client:

channel = grpc.insecure_channel(...)
stub = proto_pb2.SomethingStub(channel)
try:
    response = stub.Do(proto_pb2.Request(field="invalid"))
except grpc.RpcError as e:
    print(e)

<_Rendezvous of RPC that terminated with (StatusCode.UNKNOWN, Exception calling application: Damn!)>

So I can technically handle errors. My issue is... is there a better way? Is there a good way to change the message description? Can we change the status code?

Answer

Yes, there is a better way. You may change the status details using the ServicerContext.set_details method and you may change the status code using the ServicerContext.set_code method. I suspect that your servicer will look something like

class MyService(proto_pb2.SomethingServicer):

    def Do(self, request, context):
        if not is_valid_field(request.field):
            context.set_code(grpc.StatusCode.INVALID_ARGUMENT)
            context.set_details('Consarnit!')
            return proto_pb2.Response()
        return proto_pb2.Response(response='Yeah!')

.