Skip to content

gRPC-Go

Networking & ConcurrencyNetworking/RPCGo

What it is

The official Go implementation of gRPC — typed RPC over HTTP/2 with generated clients and servers, streaming in both directions, deadlines and interceptors.

Define services in .proto files, generate Go stubs, then implement the server interface. Interceptors provide the middleware layer for auth, logging and metrics.

Installation

go get google.golang.org/grpc

Getting started

The smallest useful thing you can do with it, and what each part means.

Server and client
type server struct {
    pb.UnimplementedBookServiceServer // forward compatibility
}

func (s *server) GetBook(ctx context.Context, req *pb.GetBookRequest) (*pb.Book, error) {
    book, err := store.Find(ctx, req.GetId())
    if errors.Is(err, ErrNotFound) {
        return nil, status.Errorf(codes.NotFound, "book %s", req.GetId())
    }
    return &pb.Book{Id: book.ID, Title: book.Title}, nil
}

// Client
conn, err := grpc.NewClient("localhost:50051",
    grpc.WithTransportCredentials(insecure.NewCredentials()))
defer conn.Close()

client := pb.NewBookServiceClient(conn)
book, err := client.GetBook(ctx, &pb.GetBookRequest{Id: "42"})
Embedding UnimplementedXServer means adding a method to the proto will not break compilation. Return errors via status.Errorf with a gRPC code — a plain error becomes an opaque Unknown.

Advanced usage

Where the library earns its place over a simpler alternative.

Interceptor for auth and logging
func authInterceptor(ctx context.Context, req any, info *grpc.UnaryServerInfo,
    handler grpc.UnaryHandler) (any, error) {

    md, ok := metadata.FromIncomingContext(ctx)
    if !ok || len(md.Get("authorization")) == 0 {
        return nil, status.Error(codes.Unauthenticated, "missing token")
    }

    start := time.Now()
    resp, err := handler(ctx, req)
    slog.Info("rpc", "method", info.FullMethod,
        "code", status.Code(err), "took", time.Since(start))
    return resp, err
}

s := grpc.NewServer(grpc.UnaryInterceptor(authInterceptor))
Interceptors are gRPC's middleware. Because they see the method name and the resulting status code, one interceptor gives you consistent auth, logging and metrics across every RPC.

Errors and fixes

The failures you are most likely to hit, and what actually resolves them.

rpc error: code = Unknown
The server returned a plain Go error. Wrap it with status.Errorf and an appropriate code from the codes package.
context deadline exceeded
The call outlived its deadline. Either raise it, or check whether the server is blocking on a slow dependency.

Best practices

  • Always embed the Unimplemented server struct so proto changes stay backward compatible.
  • Return status.Error with a meaningful code; clients switch on codes, not message strings.
  • Set deadlines on every client call — an unbounded RPC will eventually hang a caller.
  • Reuse one ClientConn; it multiplexes over HTTP/2 and is safe for concurrent use.

Background

Why it exists, and what it was reacting to.

gRPC-Go is the reference implementation from Google and the backbone of most Go microservice communication, including much of Kubernetes' internals.