Node.js gRPC Services in Style

Roman Coedo
Trabe
Published in
4 min readNov 18, 2019

In the last years gRPC has been gaining a lot of traction. In this post we are going to cover the very basics of gRPC, and jump right into building a Greeter service with grpc-node. After that, we’re going to rewrite it using Mali.

This post will assume no previous gRPC experience, so if you haven’t had the time to check what is gRPC about, keep reading!

What is gRPC?

gRPC is a new take on the RPC paradigm to build APIs that recalls the old SOAP protocol. gRPC and SOAP are similar in that both use a contract which both client and service agree upon. However, gRPC handles quite well the known SOAP weaknesses while maintaining its strengths.

Instead of XML, gRPC serializes the messages using Protocol Buffers (AKA protobuf), a Google algorithm to serialize structured data into binary. After being serialized, the data is sent over HTTP/2.

Services, rpcs and messages

A contract is defined using a .proto file. A protobuf definition file contains the interface for one or more services, the signatures for every remote procedure call in each service, and the structures of the messages that are going to be sent to the service (or received from it).

You can find a complete language guide with detailed type definitions in the Google developers guide.

Coding a gRPC service with grpc-node

We are going to build a greeter service from scratch. This is the greeter.proto file that we are going to use:

It should be pretty straightforward to read. Just a quick note: when we define the message fields, we assign a number to every field. These field numbers are used to identify the fields when the message is serialized into binary format.

Loading the proto: static vs dynamic

The next step is to load our service definition into our server. There are two ways to load a proto definition: statically and dynamically.

Using static generation we can pre-compile the proto definition into EcmaScript code (or any other supported language, actually) using the protoc command line tool. Using static generation we get some generated data structures with input validation for the messages.

Dynamic loading the .proto file is easier to understand since we can avoid the hassle of compiling the file, but we lose the input validation.

For simplicity’s sake, we’re going to use dynamic loading in our example. We are going to use the @grpc/proto-loader library to load the proto definition file dynamically:

More than one service can be defined in a single proto file. The grpc.loadPackageDefinition function loads every service definition defined in the proto file. Using these definitions we can then attach the implementations to the server:

Since we only have one service with one RPC, that is all we need to do. We are ready to start the server:

The complete implementation looks like this:

To test our service we can use grpcurl, a command line tool to make requests to gRPC services:

grpcurl is a curl-like command line tool for gRPC

If you prefer a desktop tool, BloomRPC is the Postman of gRPC :)

Using Mali

Mali is a minimalistic Node.js framework to build gRPC services. It looks a lot like the popular HTTP framework Koa.

In Mali we define remote procedure handlers as a stack of middlewares. A request cascades through the middlewares mutating a context object, attaching or parsing data and triggering side effects.

A Mali middleware is an asynchronous function that has two parameters: the context, and the next function:

The next function is an async function that invokes the next middleware in the middleware chain. Using next you can hook your code around the request.

Let’s implement a simple time middleware to illustrate this with an explicit example:

In this middleware we take the start time at the beginning of the request, we let the rest of the chain to process the request, we calculate the duration in milliseconds, and then we print it out.

Refactor our service into a Mali service

To refactor our previous gRPC server to use Mali instead of grpc-node we need to convert our greetMe handler into a middleware:

We then get a Mali instance passing it the proto file path and attach the middleware:

Just like we did before, we can use grpcurl to try it.

Plugging in some middleware

Now the cool thing about Mali is that it is easy to extend by just plugging new middleware into it. Let’s add our previous logging middleware to the service:

That’s it! now if we make a GreetMe call we will get a nice log message.

Wrapping it up

We’ve skimmed through the very, very basics of gRPC and we’ve built the easiest possible service using grpc-node and Mali.

The Mali version is much more extensible and the middleware concept is a powerful abstraction that fits really well here.

We’ve only covered unary operations here and we haven’t even mentioned how to generate the client’s code using the proto file, but that is left for future posts.

You can find all the code we wrote in this repository.

Enjoy!

--

--