gRPC is a very useful tool to use as a medium for communication or data transfer between services. It has great support for multiple languages and platforms.

What is RPC?

Remote Procedure Call (RPC) is the concept of calling a function on a program from another program, these programs can be running on different machines. REST API is an example of RPC where a client service sends an http request to a server to invoke some logic and get the response.

What is gRPC?

gRPC is a way to do RPC with a set of standards to achieve the data transfer faster and efficient. What makes it high performance is the usage of HTTP/2 as well as Protocol Buffers, which is a binary serialization format.

Protocol Buffers

When transferring data between two programs / services, the data will be serialized and deserialized. Protocol Buffers is a method of serializing structured data. It is language and platform neutral and is extensible. It’s a great way to define the data structure and services.

sequenceDiagram
    participant Client
    participant Server
    Client->>Server: gRPC Call
    Server->>Server: Process and serialize response
    Server->>Client: Response
    Client->>Client: Deserialize and continue

How to implement gRPC? ( golang example )

Prerequisites

  1. Create a go project and install the gRPC package.
go mod init github.com/adharshmk96/grpc-example
go get -u google.golang.org/grpc
  1. Create a directory for the service and message types.
mkdir helloworld
touch helloworld/helloworld.proto
  1. Define the service and message types using Protocol Buffers.

helloworld/helloworld.proto

syntax = "proto3";

package helloworld;

// Specify the Go package where the code will be generated.
option go_package = "../helloworld";

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}
  1. Generate the client and server code using the Protocol Buffers compiler.
protoc --go_out=. --go-grpc_out=. helloworld.proto
  1. Implement the service in the server.

main.go

package main

import (
    "context"
    "log"
    "net"

    pb "github.com/adharshmk96/grpc-example/helloworld"
    "google.golang.org/grpc"
)

const (
    port = ":50051"
)

// server is used to implement helloworld.GreeterServer.
type server struct {
    pb.UnimplementedGreeterServer
}

// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
    log.Printf("Received: %v", in.GetName())
    return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}

func main() {
    lis, err := net.Listen("tcp", port)
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }
    s := grpc.NewServer()
    pb.RegisterGreeterServer(s, &server{})
    if err := s.Serve(lis); err != nil {
        log.Fatalf("failed to serve: %v", err)
    }
}
  1. Create client to call the service.
package main

import (
    "context"
    "log"
    "os"
    "time"

    pb "github.com/adharshmk96/grpc-example/helloworld"
    "google.golang.org/grpc"
)

const (
    address     = "localhost:50051"
    defaultName = "world"
)

func main() {
    conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock())
    if err != nil {
        log.Fatalf("did not connect: %v", err)
    }
    defer conn.Close()
    c := pb.NewGreeterClient(conn)

    name := defaultName
    if len(os.Args) > 1 {
        name = os.Args[1]
    }
    ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    defer cancel()
    r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})
    if err != nil {
        log.Fatalf("could not greet: %v", err)
    }
    log.Printf("Greeting: %s", r.GetMessage())
}

gRPC vs REST

gRPC is a great alternative to REST API for microservices and APIs. It has a lot of advantages over REST API:

  • Performance: gRPC is faster than REST API because it uses HTTP/2 and Protocol Buffers.
  • Language and Platform Neutral: gRPC supports multiple languages and platforms.
  • Bidirectional Streaming: gRPC supports bidirectional streaming, which means both client and server can send and receive data at the same time.
  • Error Handling: gRPC has better error handling compared to REST API.
  • Code Generation: gRPC generates client and server code for multiple languages.
  • Security: gRPC has built-in support for authentication and authorization.