golang

Golang GRPC

In this tutorial, we will explore how to work with gRPC by creating an echo gRPC client and server.

What Is gRPC?

gRPC is a high-performance Remote Procedure call framework that allows developers to connect services across systems. Using gRPC, the client and server apps can communicate flawlessly.

Simply put, gRPC allows a client application to access and use methods on a server application (even in remote machines) as if it’s defined in the same application. It is a major building block for microservices.

Requirements

To follow along with this tutorial, you will need to have:

  1. The latest version of the Go compiler.
  2. Protocol Buffer compiler (protoc) version 3
  3. Go plugins for working with protocol buffers.

To install the protocol buffer compiler, run the command as provided below:

go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

The next step is to update your path so you can use the protoc commands:

export PATH="$PATH:$(go env GOPATH)/bin"

Golang gRPC Server

For this tutorial, we will build a simple gRPC server that takes the message sent by a client and echoes it back.

Start by creating a working directory:

mkdir grpc-tut
cd grpc-tut

Next, create a server.go file that will hold the code for the gRPC server:

Touch server.go

Open the file with your text editor and add the following lines:

package main
import (
    “log”
    “net”
)

In the previous code, we import the log and net packages, which will allow us to log errors and establish a listener using the net package.

Next, we will set up the main function and create a listener on port 9001/tcp:

func main() {
    listener, err := net.Listen("tcp", ":9001")
    if err != nil {
        log.Fatal(err)
    }  
}

The next step is to import the gRPC package for the Go program. This will allow us to set up a gRPC server and the endpoints we wish to serve before connecting it with the listener on TCP.

import "google.golang.org/grpc"

Back in the main function, we can create a gRPC server as shown in the following code:

grpServer := grpc.NewServer()
if err := grpServer.Serve(listener); err != nil {
    log.Fatal(err)
}

We create a gRPC server using the NewServer() method in the previous code. We then serve the server over the TCP listener we created earlier.

And with that, we have a gRPC server. However, it doesn’t do much. We can extend this by creating a simple echo application.

The application will receive the message from the client and return the same message to the client.

Echo Proto File

To set up our echo application, we will need to create a .proto file. The proto file will hold the definitions for the application.

touch echo.proto

The first entry in the proto file will be the package declaration. This prevents name collisions in other applications.

syntax = "proto3";
package echo;
option go_package = "./echo";

You can change the name to reflect the name of your package.

Once we have the package declaration, we need to add message definitions. This defines a container or structure of the message to receive from the clients:

message Message {
    string body = 1;
}

Next, we need to define the service. In our example, we call the service as echoService as shown:

service EchoService {
    rpc Echo(Message) returns (Message) {}
}

The service defines a method that a gRPC client will call. The method simply takes the message and returns the message. This creates an echo application.

Compiling the Protocol Buffers

Now, we have the proto defining for our application. Next, we need to generate the classes we will use to read and write data using the Go programming language.

We can do this using the protocol buffer compiler:

protoc --go_out=./echo --go-grpc_out=./echo --go-grpc_opt=require_unimplemented_servers=false echo.proto

The previous commands should generate the Go code required to register and call the gRPC server.

The next step is to define the RPC for the Echo method. We can do this by creating a Go file in the echo directory as:

touch echo.go

In the file, add the code as shown:

package echo
import (
    "fmt"

    "golang.org/x/net/context" // get request context
)
type Server struct {
}
func (s *Server) Echo(ctx context.Context, message *Message) (*Message, error) {
    fmt.Printf("Message recieved: %s", message.Body)
    return &Message{Body: "Hi back!"}, nil
}

The next step is to import the code inside the echo package. Go back to the server.go file and add the following import clause:

import "grpc/echo"

You will need to initialize the Go module manager for your project.

In the main server file, add the following lines to create a new chat server and register it:

s := echo.Server{}
echo.RegisterEchoServiceServer(grpServer, &s)

And with that, we have the code for the gRPC server out of the way.

gRPC Client

The next step is to build a client that can interact with the gRPC server. Start by creating a file client.go in the main directory.

touch ./client.go

Let us start with our imports. For this one, we will need the log, context, echo, and gRPC packages

import (
    "log"
    "golang.org/x/net/context"
     "google.golang.org/grpc"
     "grpc/echo"
)

Next, let us start with the main function:

func main() {
// pointer to grpc conn
var conn *grpc.ClientConn
// connect to grpc server (insecure connection)
conn, err := grpc.Dial(":9001", grpc.WithInsecure())
if err != nil {
    log.Fatal(err)
}
// close conn
defer conn.Close()
// echo service client
e := echo.NewEchoServiceClient(conn)
// message body
message := echo.Message{
    Body: "Hi",
}
resp, err := e.Echo(context.Background(), &message)
if err != nil {
    log.Fatal(err)
}
fmt.Printf("%s", resp.Body)
}

The previous code implements a gRPC client, which sends the message “Hi” and gets “Hi Back” from the server.

Testing

Once completed, run the server.go and client.go. If successful, the server should respond with “Hi back” as shown below:

You have successfully built a gRPC server and client in Go.

Conclusion

This guide serves as an absolute basic for implementing gRPC in Go. If you are new to gRPC and protobufs, it may take time to grasp the implementation. However, with a few practices and implementation, you will be in a position to build complex gRPC services. We hope you found this article helpful. Check out other Linux Articles for more tips and tutorials.

About the author

John Otieno

My name is John and am a fellow geek like you. I am passionate about all things computers from Hardware, Operating systems to Programming. My dream is to share my knowledge with the world and help out fellow geeks. Follow my content by subscribing to LinuxHint mailing list