Photo by Icons8 Team / Unsplash

This article provides a smooth introduction to gRPC framework for Node.js developers.

What is gRPC? This is high performance open source Remote Procedure Call library originally developed by Google.

What is Remote Procedure Call? Worry not, consider the following code snippet:

function getFirstName () {
    return 'John';
}

function sayHello () {
	const name = getFirstName();
    console.log('Hello ' + name);
}

In the above snippet, the function sayHello Β calls the function getFirstName to extract the name. This is obvious that the code resides within the same address space therefore it is easy to just call one function within the other.

Now consider that the function getFirstName is in another computer, you cannot just call the method from sayHello. There are a few reasons why you would want to have the methods in different computers.

One of them is in distributed systems, where micro-services communicate with each other.

That is where gRPC comes in.

gRPC framework is split into 2 main parts.

Client - This calls methods residing on the server. gRPC provides an interface that defines the parameters and return types of the methods in the server. You can have many clients. The method sayHello in the snippet above could be on the client.

Server - This is responsible for providing methods that can be called from the clients. For example, the method getFirstName could be defined in the server

The communication between the server and the clients uses Protocol Buffer binary serialisation by default.

A Β few advantages of gRPC over other RPC frameworks are, it generates client and service-side code stubs in different languages based on your service description, these stubs abstract away details such as serialisation and network communication that underly the RPC operations. It also uses efficient binary serialisation and communication based on protocol buffers and http/2 by default.

Let's setup a quick project implementing the above snippet in gRPC

Project Initialisation

  1. Create a directory greetings. This is where all our code will reside.
  2. Initialise a Node.js project using npm init
  3. Install gRPC using npm install grpc @grpc/proto-loader
  4. Create a file message.proto. This will have the Protocol Buffer definitions.
  5. Create 2 more files: server.js (which will contain the gRPC server code) and client.js (which will contain the gRPC client code).
Folder Structure

You should have a directory similar to the one shared above.

Defining the Message

Add the following snippet into message.proto file.

syntax = "proto3";

package person;
// This defines the message
message Person {
	string name = 1;
}

The first line declares the proto version this file is using. We then define the package name to name. Then we define the message named Name containing one property name. Visit the Protocol Buffer website for more info about the syntax.

Create the Server

Add the following snippet into the server.js file.

const grpc = require('grpc');
const protoLoader = require('@grpc/proto-loader');

let packageDefinition = protoLoader.loadSync('./message.proto');
let personProtocol = grpc.loadPackageDefinition(packageDefinition).person;

let server = new grpc.Server()
server.bind('localhost:8181', grpc.ServerCredentials.createInsecure())
console.log('Serving at localhost:8181')
server.start()
server.js

What does all this mean?

const grpc = require('grpc');
const protoLoader = require('@grpc/proto-loader');

These two lines import grpc and proto-loader into our server script. proto-loader is used to load and compile the proto files.

let packageDefinition = protoLoader.loadSync('./message.proto');

We then load the package definitions using proto-loader


let personPackage = grpc.loadPackageDefinition(packageDefinition).person;

We get the person package.

let server = new grpc.Server()
server.bind('localhost:8181', grpc.ServerCredentials.createInsecure())

We then create a server and bind it to localhost:8181 with insecure server credentials because we are working locally.

Note: You might have to change the port to something else if 8181 is in use in your computer.

We then start the server with server.start()

Then run node server.js and you should see this:

Expected output

Create getFirstName procedure

Now, we need to define a procedure getFirstName in our message.proto file. Procedures are defined within a service block called Greetings.

Add the following snippet in the message.proto file.

syntax = "proto3";
package name;

service Greetings {
  rpc getFirstName (NoParams) returns (Name) {}
}

message NoParams {}
...

The reason we have added NoParams message is to be able to make procedures that do not expect any parameters.

Now that we have added the definition, we need to add the implementation in our server.js

Add the following snippet in server.js just below let server = new grpc.Server() on line 7

server.addService(namePackage.Greetings.service, {
  getFirstName: (_, callback) => {
    callback(null, 'John');
  }
});
...

Create the Client

Add the following snippet into client.js file

const grpc = require('grpc');
const protoLoader = require('@grpc/proto-loader');

const packageDefinition = protoLoader.loadSync('./message.proto');
const personPackage = grpc.loadPackageDefinition(packageDefinition).person;

const client = new personPackage.Greetings('localhost:8181',
                                       grpc.credentials.createInsecure());

client.getFirstName({}, (error, response) => {
  if(!error) {
    console.log(response);
  } else {
    console.error(error);
  }
});
client.js

From line 1 to line 6 is exactly the same as on the server therefore does the exact same thing.

const client = new personPackage.Greetings('localhost:8181', grpc.credentials.createInsecure());

This creates a client, the client is connected to the address belonging to the server localhost:8181 in my case. That enables the client to make procedure calls exposed by that server.

client.getFirstName({}, (error, response) => {
  if(!error) {
    console.log('Hello ' + response.name);
  } else {
    console.error(error);
  }
});

This makes the actual call, the first parameter {] is passed onto the procedure to the server. The second is a callback which has the response or the error.

Conclusion

We have seen how to create a procedure on a gRPC server and how to call it from a client. All codebase for this article can be found here. gRPC supports many other features and languages, therefore I highly advice you to go through the official gRPC documentation.

Happy coding πŸ˜ƒ

You've successfully subscribed to Decoded For Devs
Welcome back! You've successfully signed in.
Great! You've successfully signed up.
Your link has expired
Success! Your account is fully activated, you now have access to all content.