Building a Real-Time Chat App with RPC: A Step-by-Step Guide
What is RPC?
RPC, or Remote Procedure Call, is a protocol that enables client-server applications to request procedures or function calls from a remote server. In this tutorial, we’ll explore how to build an RPC server in Go and an RPC client in Node.js.
Prerequisites
Before we dive in, make sure you have the following installed on your local machine:
- Go
- Node
- Protocol buffer
Objectives
By the end of this article, you’ll have built a chat RPC server that sends messages and returns user details. The server will have two methods: SayHello
, which accepts a message body, and GetDetails
, which accepts a user’s name and age.
Creating the RPC Server
First, create a new project directory and change into it. Then, configure Protocol Buffer by creating a chat.proto
file with the following code:
syntax = "proto3";
message Message {
string body = 1;
}
message Details {
string name = 1;
int32 age = 2;
}
message Response {
string body = 1;
}
service ChatService {
rpc SayHello(Message) returns (Response) {}
rpc GetDetails(Details) returns (Response) {}
}
This code defines a ChatService
with two methods: SayHello
and GetDetails
. The SayHello
method accepts a Message
object and returns a Response
object, while the GetDetails
method accepts a Details
object and returns a Response
object.
Generating Go Code
Next, generate Go code based on the chat.proto
file using the following command:
protoc --go_out=. chat.proto
This will generate a new folder named chat
with the Go code.
Implementing Methods
Create a new file named chat.go
and implement the SayHello
and GetDetails
methods:
“`
package main
import (
“context”
“log”
pb "chat"
)
type ChatServer struct{}
func (s ChatServer) SayHello(ctx context.Context, req *pb.Message) (pb.Response, error) {
log.Println(“SayHello Called”)
return &pb.Response{Body: req.Body}, nil
}
func (s ChatServer) GetDetails(ctx context.Context, req *pb.Details) (pb.Response, error) {
log.Println(“GetDetails Called”)
return &pb.Response{Body: fmt.Sprintf(“Hello, %s!”, req.Name)}, nil
}
“`
Configuring the Server
Create a new file named server.go
and configure the server:
“`
package main
import (
“google.golang.org/grpc”
“log”
“net”
pb "chat"
)
func main() {
lis, err := net.Listen(“tcp”, “:9000”)
if err!= nil {
log.Fatalf(“failed to listen: %v”, err)
}
srv := grpc.NewServer()
pb.RegisterChatServiceServer(srv, &ChatServer{})
log.Println(“gRPC server listening on port 9000”)
srv.Serve(lis)
}
“`
Creating the RPC Client
Create a new folder named rpc-client
and initiate an npm project. Then, install the RPC package and create a chat.proto
file with the same contents as before.
Create a new file named client.js
and implement the client:
“`
const grpc = require(‘@grpc/proto-loader’);
const chatProto = grpc.loadSync(‘chat.proto’, {});
const chatPackage = chatProto.chat;
const client = new chatPackage.ChatService(‘localhost:9000’, grpc.credentials.createInsecure());
client.SayHello({ body: ‘Hello, world!’ }, (err, response) => {
if (err) {
console.error(err);
} else {
console.log(response.body);
}
});
client.GetDetails({ name: ‘John’, age: 30 }, (err, response) => {
if (err) {
console.error(err);
} else {
console.log(response.body);
}
});
“`
Running the Client
Run the client code to make calls to the RPC server:
node client.js
This should return the following output from the server:
SayHello Called
GetDetails Called
Congratulations! You’ve successfully built an RPC server in Go and an RPC client in Node.js.