Beginners Guide in using GRPC with Golang

What is GRPC

Understanding what RPC means

Remote Procedure Call (RPC) is a protocol that one program can use to request a service from a program located in another computer on a network without having to understand the network’s details. RPC is used to call other processes on the remote systems like a local system. A procedure call is also sometimes known as a function call or a subroutine call.

How GRPC comes into play

Before diving into the meaning and uses of GRPC, I’ll start by explaining the problem GRPC solves. GRPC was created to solve the problem of communication and communicating effectively. Let’s use an example of two applications expected to carry out a simple task of sending and receiving messages. Both applications use the same language and the communication medium is essentially the same shared computer. For now, we will keep it simple and make the assumption that communication is unidirectional (communication happens in one way at a time).

  • The Sender sends a message (request) to the Receiver and waits for a response
  • The Receiver receives the message (request) and returns a response as another message

Because the 2 applications are on the same computer speaking the same language, the communication is very simple. There is no need for anything special to enable successful communication.

Now let’s change the context, imagine that we have 2 applications that are in separate computers, and use different languages. For this example, for successful communication to occur, we will need a mechanism to enable distributed communication. The mechanism will need to define some form of protocol (agreed-upon rules) and will also need to do some form of encoding and decoding of messages sent between the Sender and the Receiver. This can be seen as illustrated in the diagram below.

GRPC was developed by Google as an open-source evolution of their internal RPC technology named Stubby, and they continue to be the stewards of the official open-source project.

gRPC is a modern open-source high-performance RPC framework that can run in any environment. It can efficiently connect services in and across data centers with support you can plug in for load balancing, tracing, health checking, and authentication. It is also applicable in the last mile of distributed computing to connect devices, mobile applications, and browsers to back-end services.

Google has been using a single general-purpose RPC infrastructure called Stubby to connect the large number of micro-services running within and across their data centers for over a decade. Their internal systems have long embraced the microservice architecture gaining popularity today. Stubby has powered all of Google’s micro-services interconnect for over a decade and is the RPC backbone behind every Google service that you use today. In March 2015, they decided to build the next version of Stubby in the open so they can share what they learned with the industry and collaborate with them to build the next version of Stubby both for micro-services inside and outside Google but again, also for the last mile of computing (mobile, web, and IoT).

Interesting facts

What is Protocol Buffer

Protocol buffers are Google’s language-neutral, platform-neutral, extensible mechanism for serializing structured data. gRPC uses protobuf as a language to define data structures and services. You can compare this with a strict documentation for REST services. The Protobuf syntax is very strict so that the machine can compile.

For more information:

Interesting facts

  • Other Options: Google flat buffers, Microsoft Bond
  • GRPC uses HTTP/2 as its transfer protocol(Binary framing, Multiplexing, Server Push)

Types Of GRPC

gRPC lets you define four kinds of service method:

  1. Unary RPCs where the client sends a single request to the server and gets a single response back, just like a normal function call. rpc SayHello(HelloRequest) returns (HelloResponse);
  2. Server streaming RPCs where the client sends a request to the server and gets a stream to read a sequence of messages back. rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse);
  3. Client streaming RPCs where the client writes a sequence of messages and sends them to the server, again using a provided stream. rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse);
  4. Bidirectional streaming RPCs where both sides send a sequence of messages using a read-write stream. rpc BidiHello(stream HelloRequest) returns (stream HelloResponse);

LET’S CODE IT!!!

Here’s a basic grpc chat communication between a server and client. The first step is to define our proto file which follows the basic structure below:

Below we have our chat.proto file:

syntax = "proto3";
package chat;
message Message {
   string body =1;
}
service ChatService{
   rpc SayHello(Message) returns (Message) {}
}

To generate our protobuf file which would ultimately be our API contract between the client and server, we can use the command below:

protoc --go_out=plugins=grpc:chat chat.proto

Next, we can write out our grpc server where we define our methods previously declared in the chat.proto. Take a look at the SayHello method which receives a message from the client and responds back with a simple Hello From the Server!

package main
import (
   "chat/chat"
   "context"
   "fmt"
   "log"
   "net"
   "google.golang.org/grpc"
)
// Server ....
type Server struct {
}
// SayHello ...
func (s *Server) SayHello(ctx context.Context, in *chat.Message) (*chat.Message, error) {
   log.Printf("Receive message body from client: %s", in.Body)
   return &chat.Message{Body: "Hello From the Server!"}, nil
}
func main() {
   fmt.Println("Go Beginners Guide Using grpc")
   lis, err := net.Listen("tcp", fmt.Sprintf(":%d", 3030))
   if err != nil {
       log.Fatalf("failed to listen: %v", err)
   }
   s := Server{}
   grpcServer := grpc.NewServer()
   chat.RegisterChatServiceServer(grpcServer, &s)
   if err := grpcServer.Serve(lis); err != nil {
       log.Fatalf("failed to serve: %s", err)
   }
}

Finally, we have a simple client which creates a new chat service client, calls the server, waits for a response, and then logs the response. Find below our sample client.go

package main
import (
   "chat/chat"
   "log"
   "golang.org/x/net/context"
   "google.golang.org/grpc"
)
func main() {
   var conn *grpc.ClientConn
   conn, err := grpc.Dial(":3030", grpc.WithInsecure())
   if err != nil {
       log.Fatalf("did not connect: %s", err)
   }
   defer conn.Close()
   c := chat.NewChatServiceClient(conn)
   response, err := c.SayHello(context.Background(), &chat.Message{Body: "Hello From Client!"})
   if err != nil {
       log.Fatalf("Error when calling SayHello: %s", err)
   }
   log.Printf("Response from server: %s", response.Body)
}

Hurray, we have our basic application setup🥳, for our full working code visit the link below:

https://github.com/Xanik/basic-grpc

We use cookies for analytics and marketing purposes. By continuing to browse our website you agree to their use.
For more information please read our privacy policy.

I Understand