Skip to content

Instantly share code, notes, and snippets.

@Nearhan
Created October 11, 2017 01:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Nearhan/6bf396cec8fb45bed3a216f07fbe8f17 to your computer and use it in GitHub Desktop.
Save Nearhan/6bf396cec8fb45bed3a216f07fbe8f17 to your computer and use it in GitHub Desktop.
grpc errors

ProtoFile

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.

Server

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

Client

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment