syntax = "proto3";
package server;
message Payload {
string name = 1;
string id = 2;
}
message Response {
bool success = 1;
}
enum ErrorCodes {
None = 0;
InvalidUser = 1000;
}
service Server {
rpc Call(Payload) returns (Response);
}
We define an ErrorCodes enum which can list all of our error codes.
package main
import (
"log"
"net"
server "github.com/Nearhan/tutorials/grpcErrors/proto"
context "golang.org/x/net/context"
spb "google.golang.org/genproto/googleapis/rpc/status"
"google.golang.org/grpc"
"google.golang.org/grpc/status"
)
var (
port = ":8000"
)
type ser struct{}
func (s *ser) Call(ctx context.Context, p *server.Payload) (*server.Response, error) {
// create underlying Status struct for create a status.Status
s2 := status.FromProto(&spb.Status{
server.ErrorCodes_value["InvalidUser"],
"Invalid Error",
nil,
})
// Create an "error" from the status
return &server.Response{false}, status.ErrorProto(s2.Proto())
}
func main() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
server.RegisterServerServer(s, &ser{})
s.Serve(lis)
}
In the server we can the status package to create the underlying Status struct that grpc uses. We can use the protobuff message to attach the error code we want and a message
package main
import (
"fmt"
"log"
server "github.com/Nearhan/tutorials/grpcErrors/proto"
"golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/status"
)
const (
address = "localhost:8000"
)
func main() {
conn, err := grpc.Dial(address, grpc.WithInsecure())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
c := server.NewServerClient(conn)
r, err := c.Call(context.Background(), &server.Payload{"farhan", "123"})
// check error
if err != nil {
// convert status
s, _ := status.FromError(err)
// Check the grpc.Code with our protobuff errors.
if int(s.Code()) == int(server.ErrorCodes_InvalidUser) {
fmt.Println("GOT an ERROR!")
fmt.Println("invalud user")
} else {
fmt.Println("unknown error")
}
return
}
log.Printf("Greeting: %v", r.Success)
}
The client can convert a grpc error to a grpc code. And can check against our formated protobuff message.