Getting Started with gRPC and Node.js

September 25, 2019 - by Colin J. Ihrig

The APIs and Web services of today rely heavily on technologies such as GraphQL, REST, JSON, and the ubiquitous HTTP. In recent years, gRPC has emerged as an option for building high performance services using the remote procedure call (RPC) paradigm.

This post introduces the basics of gRPC, with an emphasis on its use with Node.js. We’ll briefly explore the underlying technologies used by gRPC before diving into some of the features gRPC provides. Finally, the post will conclude by discussing some of the architectural impacts that should be considered before adopting gRPC for your next project.

Getting Started with gRPC and Node.js

gRPC Overview

Officially, gRPC is a recursive acronym standing for gRPC Remote Procedure Calls. Unofficially, the “g” very clearly stands for Google, the company that originally created the framework. Google went on to put gRPC into the Cloud Native Computing Foundation, but still controls the project. Beyond Google, gRPC boasts a number of large users including Netflix, Dropbox, Docker, and many more.

gRPC markets itself as “a modern open source high performance RPC framework.” The “high performance” claims stem from the framework’s underlying technology choices. Unlike most web frameworks, gRPC is built on HTTP/2, not HTTP/1.1, which typically provides a performance boost on its own. gRPC also leverages protocol buffers, which serialize requests and responses in a more compact binary format. While protocol buffer serialization/deserialization incurs some processing overhead, it reduces the number of bytes sent over the network, which is often the slowest part of a web-based application.

In addition to its use of HTTP/2 and protocol buffers, gRPC supports many features, including, but not limited to, the following:

  • Unary RPCs: These RPCs behave like an asynchronous function call. Under the hood, they translate to the client sending a single request message, and the server sending back a single response message.
  • Client-side streaming RPCs: In this type of RPC, the client sends one or more request messages in a streaming fashion, while the server responds with a single response message.
  • Server-side streaming RPCs: In this type of RPC, the client sends a single request message, and the server sends back one or more response messages in a streaming fashion.
  • Bidirectional streaming RPCs: In this type of RPC, both the client request and the server response are streams of messages.
  • Compression: gRPC supports common compression schemes such as zlib.
  • Deadlines. This is essentially a request timeout. By default, gRPC requests do not time out. However, it is recommended to always configure a deadline so that requests do not consume server resources indefinitely.
  • Authentication: gRPC supports authentication at both the session and individual RPC level.

gRPC Support in Node.js

gRPC is supported across an array of languages, including C++, Java, Python, Ruby, Go, and Node.js. Many of these implementations, including the Node.js one, are built on top of a shared core library written in C. For Node.js developers, this means adding a dependency on the grpc compiled addon when building gRPC clients and servers. While certainly manageable, compiled modules do generally add a layer of complexity to projects. The gRPC team attempts to mitigate some of the hassle by providing “~130 builds of their native module for different environments.” Even with prebuilt binaries available, compilation/build issues are routinely opened on the project’s issue tracker.

In August of 2017, Node.js 8.4.0 added experimental support for HTTP/2 in core. This feature allowed the gRPC team to begin experimenting with a TypeScript implementation, culminating with the alpha release of @grpc/grpc-js in April of 2018. Unlike the compiled addon, the TypeScript implementation does not support loading protocol buffers. That functionality has moved to the @grpc/proto-loader module. Beyond that notable difference, @grpc/grpc-js aims to be a drop-in replacement for the grpc module.

Node.js 10.10.0 moved the http2 module out of experimental status. To celebrate (and avoid depending on the compiled addon), I wrote grpc-server-js, a pure JavaScript gRPC server implementation. At the time, @grpc/grpc-js did not yet support creating server applications. I’m happy to report that as of June 2019, grpc-server-js has been ported to TypeScript and upstreamed to @grpc/grpc-js. The server component is available in releases of @grpc/grpc-js starting with version 0.5.0.

Additional Considerations

The choice to adopt gRPC may impact other architectural decisions in a larger system. This is due to gRPC’s use of HTTP/2 and its own higher level protocol, which the rest of the system needs to understand and interact with. For example, off-the-shelf load balancers and other components have varying levels of support for gRPC. Performance comparisons between gRPC and non-gRPC code can also become more difficult if the same benchmarking tools cannot be used.

The biggest hurdle to gRPC adoption for many applications is its lack of support in browsers. Although many browsers now support HTTP/2, some do not. Furthermore, even browsers that support HTTP/2 do not directly expose the requisite APIs to control HTTP/2 framing, which is required by gRPC. To work around these shortcomings, gRPC-Web was developed as a browser solution. Unfortunately, gRPC-Web only supports a subset of the features supported by gRPC over HTTP/2. gRPC-Web also currently requires adding an Envoy proxy server to your system, which translates between gRPC-Web and normal gRPC traffic.

Learning More

This blog post has introduced several gRPC concepts at a high level, but has only scratched the surface. If you’re interested in learning more, please do not hesitate to reach out. Or, if you can make it to Verona, Italy on October 3, 2019, come to Node.js Day Italy and check out my talk, Getting Started with gRPC and Node.js.