GRPC in js example
gRPC Overview and Usage in JavaScript
gRPC (gRPC Remote Procedure Calls) is a modern, high-performance framework developed by Google for building distributed systems and microservices. It enables client and server applications to communicate with each other efficiently by calling remote functions (procedures) as if they were local. gRPC supports multiple languages and uses Protocol Buffers (protobuf) as its Interface Definition Language (IDL) for defining the service structure and message formats. It's widely used for microservice communication because it provides:
- Efficient Binary Serialization: gRPC uses Protocol Buffers, a binary format that is more compact and faster than JSON or XML.
- Strongly Typed APIs: gRPC enforces strict typing, making it easier to catch errors early.
- Streaming: gRPC supports various types of streaming, allowing clients and servers to send/receive a stream of data rather than a single message.
- Multiplexing: It runs on HTTP/2, which allows multiple requests and responses to be multiplexed over a single connection.
- Cross-language support: gRPC has libraries for many programming languages like C++, Go, Java, Python, JavaScript, and more.
How gRPC Works
-
Define a service: You define the service in a
.protofile using Protocol Buffers. The service specifies the functions that can be called remotely, along with their request and response types. -
Generate client and server code: Using the Protocol Buffers compiler (
protoc), you generate client and server code in the language of your choice. -
Implement server logic: On the server side, you implement the functions defined in the
.protofile. -
Client calls remote methods: On the client side, you instantiate a client that allows you to call the server’s methods like they are local.
Key Concepts
-
Protocol Buffers: gRPC uses protobuf for serialization and defining service methods. A
.protofile defines the services and messages used in communication. -
HTTP/2: gRPC uses HTTP/2 as its underlying protocol, which supports features like multiplexing, server push, and compression.
-
Streaming: gRPC supports:
- Unary RPC: A single request from the client and a single response from the server.
- Server Streaming: The client sends one request, and the server streams multiple responses.
- Client Streaming: The client streams multiple requests, and the server sends one response.
- Bidirectional Streaming: Both client and server stream requests and responses simultaneously.
Example: gRPC in JavaScript (Node.js)
Let's go through the process of setting up a gRPC service in Node.js using the official grpc or @grpc/grpc-js package.
Step 1: Define the Service in a .proto File
In a .proto file, define a service and its methods. In this example, we'll create a simple calculator service.
syntax = "proto3";package calculator;// The Calculator service definition.service Calculator {// Unary RPC: Client sends a request and gets a response.rpc Add (AddRequest) returns (AddResponse);}// The request message containing two numbers to add.message AddRequest {int32 num1 = 1;int32 num2 = 2;}// The response message containing the sum of the two numbers.message AddResponse {int32 result = 1;}
Step 2: Generate gRPC Code
Using protoc (Protocol Buffers Compiler), generate the necessary client and server code in JavaScript.
# Install Protocol Buffers compilerbrew install protobuf # macOSapt-get install -y protobuf-compiler # Linux# Generate the JavaScript and gRPC codeprotoc --js_out=import_style=commonjs,binary:. --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` calculator.proto
This will generate a .js file for the message types and the gRPC service.
Step 3: Implement the gRPC Server in Node.js
Here, we implement the server that handles the Add RPC.
// calculator_grpc_pb.js is the file generated by protocconst grpc = require('@grpc/grpc-js');const protoLoader = require('@grpc/proto-loader');const PROTO_PATH = './calculator.proto';// Load the protobuf definitionconst packageDefinition = protoLoader.loadSync(PROTO_PATH, {});const calculatorProto = grpc.loadPackageDefinition(packageDefinition).calculator;// Implement the Add RPCfunction add(call, callback) {const sum = call.request.num1 + call.request.num2;callback(null, { result: sum });}// Create and start the gRPC serverconst server = new grpc.Server();server.addService(calculatorProto.Calculator.service, { add: add });server.bindAsync('0.0.0.0:50051', grpc.ServerCredentials.createInsecure(), () => {console.log('gRPC server running on 0.0.0.0:50051');server.start();});
In this example, the add function receives the request (call.request) and responds with the sum of the two numbers.
Step 4: Implement the gRPC Client in Node.js
Now, let's create the client that calls the Add RPC on the server.
const grpc = require('@grpc/grpc-js');const protoLoader = require('@grpc/proto-loader');const PROTO_PATH = './calculator.proto';// Load the protobuf definitionconst packageDefinition = protoLoader.loadSync(PROTO_PATH, {});const calculatorProto = grpc.loadPackageDefinition(packageDefinition).calculator;// Create a client instance to call the gRPC serviceconst client = new calculatorProto.Calculator('localhost:50051', grpc.credentials.createInsecure());// Make a request to the Add methodclient.add({ num1: 10, num2: 20 }, (error, response) => {if (!error) {console.log('Sum:', response.result);} else {console.error('Error:', error);}});
The client makes a request to the Add method with two numbers (10 and 20), and the server responds with the sum (30).
gRPC Streaming Example
For a more advanced use case, you can set up a streaming service. Let's create a server-streaming service where the server sends multiple responses to a single request.
Modify .proto for Server Streaming
service Calculator {rpc AddStream (AddRequest) returns (stream AddResponse);}
Modify Server to Stream Responses
function addStream(call) {const sum = call.request.num1 + call.request.num2;for (let i = 0; i < 5; i++) {call.write({ result: sum + i });}call.end(); // Complete the stream}
Modify Client to Handle Stream
client.addStream({ num1: 10, num2: 20 }).on('data', (response) => {console.log('Received sum:', response.result);}).on('end', () => {console.log('Stream ended');});
Use Cases of gRPC
- Microservices Communication: gRPC is commonly used for communication between microservices due to its efficiency and support for multiple languages.
- Real-time Streaming: With built-in support for streaming, gRPC is ideal for use cases like chat apps, live updates, and real-time analytics.
- Interoperability: gRPC allows cross-platform, cross-language communication, which is beneficial in heterogeneous environments.
Conclusion
gRPC provides a powerful, efficient, and scalable way to build distributed systems. With features like Protocol Buffers, HTTP/2 support, and streaming, it is ideal for modern microservices architectures where performance and cross-language communication are critical. In Node.js, gRPC can be easily implemented using libraries like @grpc/grpc-js.
To be notified of new posts, subscribe to my mailing list.