gRPC with Node.js and TypeScript
The quest for optimizing the communication over the network has been going on for ages. 1990s brought us TCP/IP protocols for networking and we saw the rise of technologies such as CORBA, DCOM, and Java RMI. With the evolution of web in 2000s, HTTP started to become the defacto for communication and people started to use XML over HTTP for the communication and we saw this combination giving boom to SOAP and WSDL which provided language agnostic communication between the systems. Moving forward, as the web evolved, JavaScript and JSON started to become popular and JSON started to replace XML as the preferred wire-transfer format and resulted in an unofficial standard called REST. It did not completely replace SOAP but most of the developer focus shifted towards REST while the enterprise applications and corporates which require strict adherence to standards and schema definitions, stayed with SOAP.
The recent hotness in the industry is gRPC which is a lightweight communication protocol from Google with a support for over a dozen languages. I recently got the chance to work with gRPC in Node.js – this article is a brief introduction to gRPC and how to use it with Node.js and TypeScript.
gRPC and Proto Files
gRPC is basically a high performance RPC framework created by Google. It runs over HTTP2 and it is the default protocol that is used instead of JSON on the network. By default gRPC uses protocol buffers as IDL (Interface Definition Language) to define the structure for the service interface and structure for the payload messages. Using the IDL we can generate type safe DTO’s (Data transfer object) and client server implementations in multiple languages (like, Go, PHP, Ruby, Python, Objective-C, Node.js, Java, C, C#, Java). The types are converted to binary format when calling the remote procedures. So a server generated in C++ can communicate transparently with a client written in Java or Ruby.
The image given below gives an conceptual overview.
One of the biggest difference between gRPC and REST is the format of the payload. REST messages typically contain JSON. There’s no defined interface for the request and response so it’s safe to say that you can send anything in request and response. Where gRPC on the other hand uses defined interfaces for request and response that are defined using protocol buffers. This gives you a huge win over the REST API’s and calling the services in gRPC is just like calling a local function. Also in terms of benchmark gRPC is much faster than REST.
So enough with the talk let’s start with the actual work. We will create a greeter gRPC service that will accept your name and in reply will greet you like Hi, Adnan
Setting up a Project
Let’s begin by creating and empty project
mkdir ts-grpc
Now go inside the directory and create the directory structure similar to the one given below
Now lets install the dependencies
npm init -y
npm install grpc google-protobuf dotenv
npm install typescript @types/node @types/google-protobuf @types/dotenv --save-dev
Here’s the explanation of the packages that we have installed
- grpc to use gRPC with Node.js
- google-protobuf to use Protocol Buffers (.proto) with javascript
- dotenv to load environment variables from .env
- TypeScript and typedefinitions to help in development
Initialize typescript so that later on we can compile the project
npx tsc --init
After initializing typescript add the below content to your tsconfig.json
file
Now open the greeter.proto
file and add the below content in it
It creates one service SayHello
that accepts requests of type HelloRequest
with one field name
and gives response of type HelloResponse
. You can read more about the proto
file syntax here https://developers.google.com/protocol-buffers/docs/proto
Generating TypeScript definitions
Now let’s generate the typescript definitions against the gRPC service by using the proto file. To generate the typescript we need some kind of compiler that will translate the greeter.proto
to typescript definition. Here’s the dependencies that we have to install in order to compile the proto
file
npm install grpc-tools grpc_tools_node_protoc_ts --save-dev
Here we installed few more dev dependencies
- grpc-tools generate javascript files for the proto files
- grpc_tools_node_protoc_ts generate corresponding typescript d.ts codes according to js codes generated by grpc-tools
After installing the dependencies now we have to write a script that will loop over the all the available proto
files in the src/proto/**/*.proto
and compile them. For that open protoc.sh
and replace with below
Now we need to make this script executable so that we can actually use it. Run the below command to make it executable
sudo chmod +x ./scripts/protoc.sh
Now run the script and it will generate our typescript definition files and there respective javascript files in src/proto/greeter
. Each time you will update your proto file you have run this script to generate new typescript definitions.
./scripts/protoc.sh
After the typescript definitions have been generated, we need to tell our typescript compiler to include these files during the compilation phase. In order to do that, open src/proto/index.ts
and replace with below
You need to generate the typescript definitions and update this file whenever you create new proto files.
Creating handlers
Let’s write our greeter handler to define our SayHello
service so open src/handlers/greeter.ts
and replace it with below. It creates and handler that will handle all the requests against the greeter service. So later on if you will add new rpc services in your proto file greeter.proto
, you have to define there respective definition here in this handler.
See sayHello
it has the implementation of our SayHello
rpc service. Which is getting name from the request HelloRequest
and provides response of type HelloResponse
Writing the Server
Now let’s write a gRPC server. Open src/server.ts
and replace with below
As you can already guess from the code, we are just creating an instance of gRPC server, registering our greeter service handler and then just starting the server.
Testing our Implementation
Now let’s test it. So to test it we have to update our package.json
scripts
section. So add following.
...
"scripts": {
"build": "npx tsc --skipLibCheck",
"start": "npx tsc --skipLibCheck && node ./dist/server.js"
}
...
Now open terminal and run the build command. This will create a dist
folder and will compile typescript to generate javascript files.
npm run build
Once the build is finished, let’s test our implementation by running the server. Run the command below to start the server
npm run start
If everything goes well, you should see the message gRPC listening on 50051
In order to test our server, I am going to use BloomRPC which is a GUI client to test RPC services.
Follow the installation guide, import the greeter.proto file, update the URL to be 127.0.0.1:50051
and click the PLAY icon and you will see the output similar to the one given below
And that wraps it up. You can find the source code from the article here.
Feel free to leave your feedback or questions in the comments section below.