
A Node.js Developer's Guide to RPC
Hello! If you're hearing about RPC for the first time, don't worry. This article will guide you from scratch to understand what RPC is and how to implement a simple RPC system using Node.js.
Let's assume we have a function that calculates the sum of two numbers:
// Local function
function add(a, b) {
return a + b;
}
const result = add(3, 5); // Direct call
console.log(result); // Output: 8This is the most familiar way of calling a function—a local call, where all the code runs within the same process.
What if your add function needs to run on a different server? That's the problem RPC aims to solve.
RPC (Remote Procedure Call) is a technology that allows you to call a remote service as if it were a local function.
- Local call: Directly asking a colleague, "Could you get me a coffee?"
- Remote call: Sending a message to a colleague in another office, "Could you get me a coffee?"
The goal of RPC is to make the remote call feel as simple as a local one.
Let's use Node.js to build a basic TCP-based RPC system.
For simplicity, we will assume each TCP packet is a complete JSON request. In a real-world scenario, larger requests can be split into multiple packets, which would require more complex parsing.
// server.js
const net = require('net');
// Our "remote" methods
const methods =
// client.js
const net = require('net');
class
- Start the server first:
node server.js- Then, run the client:
node client.jsYou'll see the client successfully call the remote methods and get the results!
Let's use our simple implementation to understand a few key concepts:
- Serialization: Converting data into a format that can be transmitted (like a JSON string)
- Deserialization: Converting the received data back into its original format
In our example:
// Serialization
const request = JSON.stringify({ method: 'add', params: [1, 2] }
We used Node.js's net module to establish a TCP connection. In practice, RPC can use various protocols:
- TCP: Better performance
- HTTP: More versatile
- WebSocket: Suitable for browsers
Every call has a clear request and a response:
// Request format
{
method: 'method_name',
params: [param1, param2],
id: unique_identifier
}
Let's improve on our simple implementation by adding error handling and more features.
// better-server.js
const net = require('net');
const methods = {
// better-client.js
const net =
- Better Error Handling: The server can catch errors and return them to the client.
- Timeout Mechanism: The client has a 5-second timeout.
- Data Integrity: We now handle cases where the data is split into multiple packets.
- More Robust Protocol: The response now includes an
errorfield.
While we built a simple RPC from scratch, in a real-world project, you'll use a mature RPC framework. Let's see how to use gRPC.
npm install @grpc/grpc-js @grpc/proto-loaderCreate a calculator.proto file:
syntax = "proto3";
service Calculator {
rpc Add (Numbers) returns (Result);
// grpc-server.js
const grpc = require('@grpc/grpc-js');
const protoLoader = require
// grpc-client.js
const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');
const packageDefinition