Building a gRPC Client in Go

Introduction

In this article, we will take a look at how to create a simple gRPC client with Go. We will be using this client to interact with the gRPC server that we created in my previous post. So let’s get into it!

Motivation

This is the second part of an articles series on gRPC. If you want to jump ahead, please feel free to do so. The links are down below.

Introduction to gRPC
Building a gRPC server with Go
Building a gRPC client with .NET

Building a gRPC client with Go (You are here)
Building a gRPC client with .NET

Please note that this is intended for anyone who’s interested in getting started with gRPC, therefore, we will keep things simple.

Plan

The plan for this article is as follows.

Scaffold the client-side stubs and go modules
Implementing the gRPC client
Communicating with the server

In a nutshell, we will be generating the client for the server we built in our previous post.


In the above diagram, we will look at how to achieve the components on the left side.

? As always, the completed code can be found at: https://github.com/sahansera/go-grpc/tree/main/client

Creating client-side Stubs and Go modules

We will be using the same Protobuf files that we generated in our previous step. If you haven’t seen that already head over to my previous post.

We will create a new folder called client at the root of the project and initialize it with a new Go module.

mkdir client && cd client
go mod init bookshop/client

Once we have the go modules we can now generate the Protobufs for the client side.

protoc –proto_path=proto proto/*.proto –go_out=client –go-grpc_out=client

This is very similar to our previous blog post.


Implementing the gRPC client

Now that we have the modules we can go and implement the code for the client.

In order for us to talk to the server, we first need to create a connection. For that, we can use the grpc.Dial() method.

? Note that we are not using TLS here, however, in production environments you must!

The rough skeleton of the client code looks like the following.

main.go

// …
func main() {
conn, err := grpc.Dial(“localhost:8080”, grpc.WithTransportCredentials(insecure.NewCredentials()))

// Code removed for brevity

client := pb.NewInventoryClient(conn)

// Note how we are calling the GetBookList method on the server
// This is available to us through the auto-generated code
bookList, err := client.GetBookList(context.Background(), &pb.GetBookListRequest{})

log.Printf(“book list: %v”, bookList)
}


The explanation of this code is as follows:

grpc.Dial is a way to create a client connection to a given target. In our case, we can send in the path of our server along with its port. Note how we are passing in an option to turn off TLS by using WithTransportCredentials

We then call the server procedure/method just as you’d normally do when calling a local method in your program. This is the thing that sold me on gRPC because we know exactly what we have to pass and how to invoke the call.
Now on the server side, we have a request handler that will respond to the incoming requests.
We finally log the response that we got from the server.

Communicating with the server

And in the terminal, we will get the following outputs.


Nice! as you can see it’s not that hard to get everything working ? One thing to note is that we left out the details about TLS. But I guess, that will be posted for another day ?

Conclusion

In this article, we looked at how to reuse our Protobuf files to create a client to interact with the server we created in the previous post.

I hope this article cleared up a lot of confusion that you had about gRPC. Please feel free to share your questions, thoughts, or feedback in the comments section below. Until next time ?

References

https://www.youtube.com/watch?v=RHWwMrR8LUs&ab_channel=NicJackson
https://learning.oreilly.com/library/view/grpc-up-and/9781492058328/
https://grpc.io/docs/languages/go/basics/#client

Flatlogic Admin Templates banner

Introduction to gRPC

Intro

If you have built RESTful or other OpenAPI-like APIs for some time and wondering what’s next for you, then you have come to the right place. This article series discusses leveraging gRPC to build your next API, even multiple services. We will initially look at the main concepts from a high-level view and then move on to the implementation aspects of it.

Motivation

There are many tutorials on getting started there. But the main issue I faced was either, they even made me more confused as there was a lot of contexts lost in the process and brought in way too many third-party libraries or explained a bunch of steps without emphasizing how different pieces work together. Therefore, I thought to create a guide for anyone who’s interested in getting started with gRPC from a hands-on perspective.

This article is the first part of a series on gRPC. The links are down below. If you want to jump ahead, please feel free to do so.

Introduction to gRPC (You are here)
Building a gRPC server with Go
Building a gRPC server with .NET
Building a gRPC client with Go
Building a gRPC client with .NET

Background

One of the popular choices for building APIs nowadays is creating a RESTful service. However, before even coming to REST API, we need to look back to see other forms we used to have in the past.

SOAP – Popular back in the late-90s for building service-oriented architectures (SOA) systems which are known for exchanging bloated XMLs. The benefits were detrimental for distributed applications where the schema was rigid.

REST – Promoted the resource-oriented architecture (ROA)-style distributed applications. Often bulky with JSONs, and everything that the service provides is represented as resources (Eg: /api/v1/users/ or api/v1/books/1234 etc.). Sometimes this could result in too exposing too little data or too much data at the cost of making multiple HTTP calls.

GraphQL – GraphQL takes a step further and exposes a single endpoint that you can use to query or mutate the data through HTTP verbs. It’s still a request-response model and based on the text-based transport protocol, HTTP 1.x.

What if I want to have some bi-directional communication? None of the above solved that. Then we got technologies like WebSockets and Server Sent Eventing.

WebSockets – Built to support bi-directional communication over a single TCP connection. Known to be a very chatty protocol often sending packets back and forth. If you want to know about WebSockets, here is an article that I wrote.

Server Sent Eventing – Another paradigm where the server sends messages to the client once the initial connection has been set up by the client.

There’s a recurring theme going on in the above technologies. It could be issued with messages being (bulky, not strongly typed etc.), inefficient protocols (text-based such as HTTP 1.x etc.).

Hello gRPC

gRPC was born to address some of the challenges we face in the above approaches. In 2015 Google released gRPC to the open-source world. The idea behind gRPC is to have a single client library – Whoever is maintaining gRPC will maintain the client libraries. Because HTTP/2 works on binary format. So the idea is to abstract away the HTTP/2 stuff from you. The developers only have to define their service contracts through requests, responses and RPC calls, and the gRPC framework will handle the rest for us.

? Even before we start learning about gRPC, you must have also thought about what the “g” in GRPC mean? Some say it stands for “Good”; others say it stands for “Google”. You know what? It doesn’t matter as it doesn’t provide more context. You can find all the different variations here, which is, by the way, hilarious! ?


Source: https://grpc.io/docs/what-is-grpc/introduction/

RPC has been around for some time; however, gRPC approaches RPC much cleaner way.

Another term that you’d come across when learning gRPC is inter-process communication or IPCs. GRPC is mainly built to cater to inter-process communication that lets you connect, invoke, and operate, an excellent choice for micro-services like applications. In distributed computing realm, inter-process communication or, in short, IPC refers to passing messages (synchronously or asynchronously) where any application or a node can act as both client and a server.

Does this mean I should replace my current APIs, which are customer-facing? Absolutely not. If you have customer-facing APIs, they should be actually

Protocol Buffers

They are a language-agnostic way to define what your service does. These are commonly known as “IDLs” or Interface Definition Language(s).

So the steps are,

You write the messages. These messages have statically typed fields
You write your services by defining what comes in, what goes out
Compile the proto files and generate the client libraries for your application

It’s also worth mentioning that Protocol Buffers are not the only way to define our IDLs. There are other formats like FlatBuffers, Bond etc.

This is what a protocol buffer looks like:

syntax = “proto3”;

message Book {
string title = 1;
string author = 2;
int32 page_count = 3;
optional string language = 4;
}

message GetBookListRequest {}
message GetBookListResponse { repeated Book books = 1; }

service Inventory {
rpc GetBookList(GetBookListRequest) returns (GetBookListResponse) {}
}

The above is an example that we will use throughout this blog series.


The first line specifies the Protobuf version we will be using. It will be set to proto2 if you don’t specify it.
The Book is a message definition with some statically typed fields such as title, author etc.

GetBookListRequest and GetBookListResponse are also messages composed of the Book type we defined above.
Inventory is a service that says what methods we expose to the remotely invoked clients.

There are many advantages of using Protobufs compared to something like JSON. Once you write the definitions for your service, you can share them with other teams and use them to generate stubs/code that can interact with your service.

Another advantage is that Protobufs are binary encoded. The payload is smaller than JSON, which means it would be efficient to send. This also means that it will use fewer CPU cycles to serialize/deserialize the messages.

gRPC Server & Client

Now that we have the Protobuf definitions for our service, we could generate the Server side and Client side implementations using the Protoc compiler.


We first create the definition of the service with a .proto file
We then generate the server-side code in our preferred language (Go, C#, Java etc.). This code includes the boilerplate code to serialize, deserialize, functions for receiving and responding to messages.
We then generate the client-side code in our preferred language (doesn’t have to be the same language we chose for the server). This includes methods that we can invoke on our server with additional code to serialize, deserialize messages.
Depending on which gRPC mode we choose, the client-server communication happens over an HTTP/2 connection. We will discuss more on these modes in the next section.

gRPC Modes

There are 4 modes of gRPC communication styles. Following are their brief introductions. Feel free to go more in-depth by reading through the official docs.

Unary RPC – More like our traditional APIs where we send a request and receive a single response.
Server Streaming RPC – Client sends a request and reads until the server stops sending messages via a stream.
Client Streaming – Reverse of the above, the client sends messages through the stream and waits for the server to read and return a response.
Bidirectional streaming RPC – Pretty much both (2) & (3) combined – both client and server streams messages both ways.

Pros and Cons

Any technology comes with a set of advantages and disadvantages. Whether you choose to use gRPC might depend on some of these factors.

Pros

Efficient for inter-process communication with all the good stuff that comes with HTTP/2.
Well defined interfaces to be able to communicate also while supporting polyglot development.
Code-generation of client and server stubs with strong types.

Cons

It may not be suitable for external-facing services since most web browsers’ support is limited.
Changing the service definitions might require rework and regeneration of code.
Could be a steeper learning curve compared to other RESTful or GQL like architectural styles.

Conclusion

In this article, we looked at gRPC from a high level. In the next article, we will look at how we can put these into action and generate a gRPC service with Go. Feel free to let me know any feedback or questions. Thanks for reading ✌️

References

https://developers.google.com/protocol-buffers/docs/proto3
https://www.oreilly.com/library/view/grpc-up-and/9781492058328/

https://github.com/grpc-ecosystem/awesome-grpcyou

Flatlogic Admin Templates banner