I am wondering what is the best way to deal with grpc status code and response when we sent back to the user?
func (us *customerService) FetchResponse(ctx context.Context, request *custPbV1.CustomerRequest) (*custPbV1.CustomerResponse, error) {
meta := service.MetadataFromContext(ctx)
clientId := meta.ClientId
if clientId <= 0 {
msg := fmt.Sprintf("could not retrieve client info for clientId:%d", clientId)
// is this right way to return it?
return nil, status.Error(codes.NotFound, msg)
}
resources := request.GetResources()
if len(resources) == 0 {
// is this right way to return it?
err := status.Error(codes.InvalidArgument, "value cannot be null. (Parameter 'resources')")
return nil, err
}
return us.GenerateCustomerInfo(clientId, resources)
}
My proto is very simple -
service CustomerService {
rpc FetchResponse(CustomerRequest) returns (CustomerResponse) {};
}
message CustomerRequest {
string resources = 1;
}
message CustomerResponse {
string proc = 1;
string data = 2;
}
GenerateCustomerInfo
method will return CustomerResponse
and error
both. But if there is a error then what status code it will be? I am trying to figure out what is the standard basically people follow while returning grpc status code and response back to user. Is it mandatory to return status code back to client or no?
Is it good idea to have error property in response object as well? Any example that demonstrates best practice on how to return grpc status and response back will be useful for me.
CodePudding user response:
This is totally fine to do it like this:
err := status.Error(codes.InvalidArgument, "value cannot be null. (Parameter 'resources')")
return nil, err
This will tell your client that there is an error and with that knowledge the client can check the status code and the status message as following:
resp, err = server.FetchResponse(context.Background(), req)
s, ok := status.FromError(err)
if ok { // there is an error
fmt.Printf("Code: %d, Message: %s\n", s.Code(), s.Message())
}
GenerateCustomerInfo method will return CustomerResponse and error both. But if there is a error then what status code it will be?
For the GenerateCustomerInfo
we don't have much info to reproduce but in my opinion you should just return something like:
return &custPbV1.CustomerResponse{
Proc: "YOUR_PROC",
Data: "YOUR_DATA",
}, nil
by returning nil
in the error, you will show the client that there is no error and in the previous code give the ok
will be false.
Is it good idea to have error property in response object as well?
for that, you definitely could add an error property, but is there any need for that? you can already have a StatusCode and a Message. It would just increase the size of your payload unnecessarily.
But if GenerateCustomerInfo return any error then what status code should I return back? Do I need to define that too?
Given an potential implementation of 1GenerateCustomerInfo` like:
func GenerateCustomerInfo() (*pb.CustomerResponse, error) {
// some code
if err {
st := status.Error(codes.Internal /*or other*/, "a message")
return nil, err
}
return &pb.CustomerResponse{
Proc: "",
Data: "",
}, nil
}
it will basically return either a CustomerResponse
or nil
which is totally what the parent function need.