gRPC is a new technology that is gaining more and more popularity, leading companies use it as the default way to communicate between internal services, in this blog post I will introduce gRPC, explain about its fundamentals, and demonstrate a client/server coding example in Node.js.

gRPC Motivation

Nowadays Microservices are everywhere, this kind of architecture has many advantages, for example services can be scaled separately, services can be developed in different languages and more.
Huge amount of data flows between those services, hence they must be able to communicate with each other – for that we need to define an API contract, but building an API requires us to consider many important stuff, such as:

  • The client/server communication protocol (REST, graphQL, SOAP, etc)
  • The payload format (JSON, XML, Binary, etc)
  • The data modeling
  • How to handle errors
  • How to authenticate your users
  • Scale – what happens when your service needs to handle large amount of concurrent requests

Sounds like a lot of work! Well… this is exactly what the gRPC framework is trying to resolve, the contributors of gRPC came to the conclusion that client server communication should be efficient and simple, they designed a framework that lets the developers focus on the core logic of the application and the framework will do the rest…

So what is gRPC?

gRPC (google Remote Procedure Call) is a technology developed by Google, it was released in 2016 and is now part of the Cloud Native Computing Foundation (CNCF open source projects) – like Prometheus and Kubernetes.
It uses HTTP/2 as a communication protocol, and protocol buffers as a messaging format.
The project maintains official client libraries for 11 programing languages, it’s fast and efficient, supports low latency and bi-directional streams. It is language agnostic with pluggable features like authentication, load balancing, loggings and monitoring.

In gRPC the client invokes methods in a remote server without specifying the details of the server, unlike REST for example when the client needs to specify the address and resource (i.e <BASE_URL>/users/:id), in simple words it looks like the client calls to a method that is located directly in the client app. gRPC is based on the RPC idea of defining a service, declaring the methods and their schema objects.
The server must implement those methods, while the client has stubs that provide the same methods as the server.
gRPC is used by top companies like: Netflix, Lyft, Cisco, Block (formerly Square) which are also contributors of the project and of course Google themselves.

What makes gRPC efficient?

There are two main things that makes gRPC so efficient

Protobufs

In high level protobuf is a mechanism developed by google that supplies tools to define a schema that is going to be serialized/ deserialized to binary format. Other than that, it supplies rules to support backward and forward compatibility for API evolving.
Using binary format as the request-response payload is a huge advantage, since binary format is closer to how data is represented by machines – the serialization/ deserialization is faster and consumes less CPU, which is very important for devices with limited network conditions like mobile and IoT devices as it improves the battery life and the latency. In addition, binary format compared to JSON format is much smaller hence it improves the network utilization.
protobuf schema is defined in a .proto file as shown in this example:

The syntax keyword defines the version, the latest protobuf version is 3.
A message is an object that defines the schema and can include nested messages, in this case we have an Animals message that contains an array of messages from the type Animal.
The Animal message itself has strongly typed fields which are numbered, the numbering helps the encoding process to binary format.
protobuf offers a protoc compiler for each programing language, its output is an auto generated code that includes interfaces and functions to create instances of the messages, populate them with data and then serialize them to binary format.
in gRPC all of these steps are being done by the framework itself, all we have to do is just to define the proto file which we will see in the coding example.

HTTP/2

HTTP/2 was released in 2015 after being tested for many years by Google, because of the way it’s designed it supports headers compression which makes the packets even smaller and saves bandwidth, the frames are in binary format which is very performant, thus it works great with protocol buffers.
The most important feature is multiplexing – unlike HTTP/1.1 which needs to open a single TCP connection for each request-response, in HTTP/2 multiple requests/ responses are sent in parallel over a single TCP connection, which reduces latency and improves network utilization.

So the advantages of HTTP/2 and protobufs are crystal clear and we get all these benefits with all the best practices as is! without any configuration, just by using the gRPC framework.

API types of gRPC

gRPC has 4 API types that cover all the cases we need:

types of gRPC API's

Unary – Normal request response, very similar to REST but works with protobufs and HTTP/2 under the hood.
Client streaming – The client send messages in a stream to the server and when the client finishes the server sends response.
Server streaming – The client asks for a resource from the server and the server responses with a stream of messages.
BI – directional streaming – Both client and server are sending messages in the same TCP channel.

Let’s get hands-on

Now after we understand why gRPC was invented and how it works let’s get our hands dirty and implement a client/ server example in node.js.
Our App will be an ‘Employees App’, where we will implement 2 methods: Unary and Server stream.

employees methods
As shown in the figure above, we will have a unary method that will add employees to in memory database, and another server stream method that will read all the employees one by one in a stream instead of a big array chunk.

Setting up our project

We will need node.js and NPM installed on our machine, in case you don’t have it you can download it here.

Now create a folder for the project:
mkdir employees-app       

Move inside the project and initialize our node environment:
cd employees-app && npm init -y

Next, install our dependancies:
@grpc/grpc-js – the gRPC library for node.js that supplies the server and client functionality
@grpc/proto-loader – the package to load our proto files and convert it to the messages objects and methods
npm install @grpc/grpc-js @grpc/proto-loader

Defining our contract

First we need to define our protobuf contract, for this we need to create the proto file and implement the schema.
touch employees.proto

Our proto file will look as follow:

Let’s explain it, we are using the latest version which is proto3, we then declare a package and name it employees, the package name is the identifier of the proto file and we will use it to load it later.
Below we are declaring the Service which includes the methods that we will need to implement in our server, we have 2 methods:
rpc addEmployee (EmployeeRequest) returns (EmployeeResponse) {} – which implements unary API that sends EmployeeRequest from the client and receives EmployeeResponse from the server.
rpc readEmployees (Empty) returns (stream EmployeeResponse) {} – which implements server streaming API, the stream keyword in the response defines that this is a server stream, the method sends empty request and gets a stream of EmployeeResponse.

Our request and response messages are defined in the bottom of the file:
– EmployeeRequest includes name and last_name which are strings.
– EmployeeResponse includes name, last_name and email which are strings and id which is an integer.

Implementing the server

The server will run on a gRPC port and will implement the methods that are defined in the service of the proto file.
Let’s go ahead and create it.

touch server.js

Our server boilerplate will look as follow:

We first import the @grpc/grpc-js which is the official gRPC library for node.js and the helper package @grpc/proto-loader that deals with the proto file.
const grpc = require("@grpc/grpc-js");
const protoLoader = require("@grpc/proto-loader");

We then use the helper function protoLoader.loadSync to load the employee package definition with the default configurations while supplying the path to our proto file.
The package definition we got, is then being loaded to the grpc object
const employeesProto = grpc.loadPackageDefinition(packageDefinition).employees;
Now we have an object that contains the methods and the interfaces that we defined in the proto file and we are ready to use it.
We are creating a new server instance, adding the Employee service and its methods, finally we are running it on port 50050.

It’s time to implement our methods:

Our unary method addEmployee accepts the arguments call and callback, the call object holds the info of the entire call/channel and the callback function returns the response to the client.
The implementation is simple, we are destructing name and lastName from the request, composing the employee object based on the schema that is defined in our proto file (EmployeeResponse), pushing it to our in memory database  (the employees array), at last we are sending the specific employee response back to the client.

Our server streaming method readEmployee accepts only single argument which is the call object because it uses the stream itself to send responses to the client.
In the implementation we are looping over the employees database and we’re using call.write to stream the messages to the client. (a sleep is added for better visibility).
After all the employees data was streamed to the client, the server is closing the call and notifying the client about it, so the client can gracefully shut down.

Our final unified server file should look like this:

Implementing the client

The client will connect to the gRPC server and will invoke methods.
Let’s create it.
touch client.js

The client boilerplate will look as follow:

The loading process of the proto file is similar to what we have done in the server, since they both need to apply the protobuf contract.
The only difference between them is that instead of creating a server, we are creating a client instance so it will be able to invoke methods that are defined in our Employee service, this is done by:
const client = newemployeesProto.Employee("localhost:50050",grpc.credentials.createInsecure());

Now we can add the code that invokes the methods to our client.js file:

As you can see we have a condition that if we run the client with args (name, lastName) it will invoke the unary method and will forward the payload to the server in order to compose a new employee, otherwise the server stream method will be invoked.
Our unary stub in the client invokes the addEmployee method and passes the EmployeeRequest message, and a callback that returns from the server after success or failure.
Our server streaming stub starts a stream with the server, and gets a reference to this stream, as declared in:
const call = client.readEmployees();
We then register to  the events of this call:
– call.on(“data”) which will be called on each response that we get in our stream from the server, in this case we are getting the EmployeeResponse and logging it to the screen.
– call.on(“end”) which indicates the server finished to stream all its data and we can gracefully shutdown the client.

Running our app

We have implemented our employees app, let’s run it!
Open 2 terminal windows and first run the server
node server.js

You should see the following message:
-> employees-app node server.js
gRPC Server started...

Now Let’s add our employees by running the client from the second terminal window and invoking the unary method, We will add 3 employees as follow:
-> employees-app node client.js tony stark
Employee tony stark was added successfully

-> employees-app node client.js peter parker
Employee peter parker was added successfully

-> employees-app node client.js steve rogers
Employee steve rogers was added successfully

It’s time for the big moment! let’s get all our employees in a stream, for that simply run the client.js file without args at all.

node client.js
and Voila! we got our employees in a stream.

Employee details {"id":1,"email":"tony.stark@lusha.com","name":"tony","lastName":"stark"}

Employee details {"id":2,"email":"peter.parker@lusha.com","name":"peter","lastName":"parker"}

Employee details {"id":3,"email":"steve.rogers@lusha.com","name":"steve","lastName":"rogers"}
Server has closed the call, Bye bye...

Wrapping up

In this blog post, we introduced gRPC, we explained what problem gRPC tries to resolve and motivation of it.
In addition we covered advanced topics like protocol buffers and HTTP/2 which are the gRPC fundamentals and what makes it so efficient.
We then moved to a hands on example where we implemented client server application with the gRPC node.js library.
But still, there are a lot more to discover, I encourage you to read the documents, posts and the roadmap of the official project, get confidence by developing your own apps.

5 1 vote
Article Rating
Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments

Developer? Join Lusha - Apply today!