gRPC server error handler golang
Asked Answered
S

3

12

I want know about good practices with golang and gRPC and protobuf.

I am implementing the following gRPC service

service MyService {
   rpc dosomethink(model.MyModel) returns (model.Model) {
     option (google.api.http) = { post: "/my/path" body: "" };
   }
}

I compiled the protobufs. In fact, the protobuf give us a httpproxy from http to grpc.

The code to implement this service:

import "google.golang.org/grpc/status"

func (Abcd) Dosomethink(c context.Context, sessionRequest *model.MyModel) (*model.Model, error) {

   return nil, status.New(400,"Default error message for 400")
}

I want a 400 http error (in the http proxy) with the message "Default error message for 400", the message works, but the http error always is 500.

Do you know any post or doc about this?

Scifi answered 2/8, 2017 at 8:13 Comment(0)
M
13

You need to return empty model.Model object in order for protobufs to be able to properly serialise the message.

Try

import "google.golang.org/grpc/status"

func (Abcd) Dosomethink(c context.Context, sessionRequest *model.MyModel) (*model.Model, error) {

   return &model.Model{}, status.Error(400,"Default error message for 400")
}
Musetta answered 2/8, 2017 at 10:12 Comment(1)
Thanks you, now it's working. I would like to add as a comment that the codes to be used are not directly http (200, 300, 400 ...) if not the ones that come in grpc/codes packageScifi
N
11

Error Handler:

"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
return data, status.Errorf(
            codes.InvalidArgument,
            fmt.Sprintf("Your message", req.data),
        )

For need more info about the error handling take a look below links.

https://grpc.io/docs/guides/error.html

http://avi.im/grpc-errors/

Neurosurgery answered 25/1, 2019 at 9:23 Comment(1)
I am doing same, but doesn't work for me.Bootstrap
G
0

In gRPC, we should never return error in success response. It should be like either we return the successResponse or we return the errorResponse. If we are return for example errorResponse then the successResponse will be nil.

Golang has a package called status which is widely used for error handling. It has an internal function Error() which converts it to error object which is returned.

// status.proto
message Status {
  // The status code, which should be an enum value of [google.rpc.Code]
  int32 code = 1;

  // error-message
  string message = 2;

  // A list of messages that carry the error details.
  repeated google.protobuf.Any details = 3;
}

So, We should send grpc error code in code field. We can send a general message related to error occured or ErrorCodes like "VALIDATION_ERROR", "AUTH_ERROR", etc. in message field. And, the additional information or stack trace or developer error message should be sent in details field.

Example 1:

 err := status.Errorf(codes.InvalidArgument, "First Name is required")

Example 2:

 //error.proto
 message ErrorDetails {
   string code = 1;
   string additional_info = 2;
 }

 err := status.Errorf(codes.InvalidArgument, "First Name is required")
 err, _ := err.WithDetails(&ErrorDetails{
   Code: "VALIDATION_ERROR",
   AdditionalInfo: "Error occured at third-party API"
 })

We can also create our own custom struct similar to Status which should implement 2 methods - Error() and GRPCStatus() and gRPC will take care of rest.

Note: In case, we are using grpc-gateway and serving both grpc and http servers via proxy. In that scenerio, we can create a custom interceptor using WithErrorHandler to covert status object to our more client-friendly error object.

Guillermo answered 12/12, 2023 at 12:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.