Client Push API with gRPC
gRPC allows a one-word implementation to write an API where a client sends a continuous stream of data to the server
This is done due to the fact that gRPC runs on HTTP2, so resource multiplexing comes into the picture and helps client keep pushing data while the server listens for it and responds as per requirement.
Resources
I have committed all the protofiles in detailed branches at this github repository for your perusal
This is the file structure that I have followed while designing this API.
root_folder/
|-- client/
| |-- client.js
|-- node_modules
|-- protos/
| |-- avg.proto
|-- server/
|-- index.js
|-- protos/
|-- avg_pb.js
|-- avg_grpc_pb.js
0. Sample Problem
In this exercise, we will be building a Calculate the Average of streamed numbers using client streaming
The function takes a stream of Request messages that have one integer each, and returns a single Response that represents the average of all the nummbers streamed to it
1. Writing the protofile
This is pretty basic and will involve
TYPE | HTML | |
---|---|---|
gRPC Request | STREAM OF INTEGERS |
Simple message object |
gRPC Response | INTEGER |
Simple message object |
Service | FUNCTION |
rpc ComputeAvg(stream AvgRequest) returns (AvgResponse){} |
syntax="proto3";
package avg;
service AvgService{
rpc ComputeAvg(stream AvgRequest) returns (AvgResponse){}
}
message AvgRequest{
int32 num = 1;
}
message AvgResponse{
double average = 1;
}
Here, the stream keyword next to AvgRequest is of key importance as it tells gRPC to generate code accordingly such that the function called from the stream of client request will return single response.
2. Generate the protofiles
Packages required : protoc, grpc-tools
1. grpc-tools
npm i grpc-tools
We get AvgServiceService and AvgServiceClient generated from the "grpc-tools" module that will act on our proto to create the client and service (server)
Output file ⇒ PACKAGENAME_grpc_pb.js
2. protoc
Whereas, the protoc will simply generate the Request and Response objects and give us getters and setters on them
Output filename ⇒ PACKAGENAME_pb.js
sudo protoc -I=. ./protos/avg.proto \
--js_out=import_style=commonjs,binary:./server \
--grpc_out=./server \
--plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin`
Here the inside the main project directory, we have a client, server and protos subdirectory. Currently, we are generating the API from proto file in the protos directory into the protos subdirectory inside the server directory
3. Setup a gRPC server
npm i grpc google-protobuf
Import the necessary dependencies. Here,
- avg_pb ⇒ Contains all the details about the request and response object.
- avg_grpc_pb ⇒ Will help the grpc server create an API from the proto generated code.
Define the function that will handle the request and return a response. This function is what we defined in the proto file and this is also the function that will be callled from the client
Here the call.on() methods allow us to basically monitor the stream sent from the client for proper response and error handling.
4. Setup the Client Side
Import the necessary dependencies.
- avg_grpc_pb ⇒ Contains proto generated code that will help us setup the client and link it to the server functions we have defined
- avg_pb ⇒ Contains code to help us access and work with the request object
Setup a client using the proto generated code
Add service to server and start it
//* Setup a server
const server = new grpc.Server()
server.addService(avgService.AvgServiceService, { computeAvg })
//? START THE SERVER
const URL_ENDPOINT = "127.0.0.1:50051"
server.bind(URL_ENDPOINT, grpc.ServerCredentials.createInsecure())
server.start()
console.log(chalk.green(`Server running on ${URL_ENDPOINT}`))
Conclusion
Congratulations ! You are now equipped with the futuristic skills of client-push-server-stream type API designing. Thanks a lot for reading this blog. If you like more content like this, subscribe to my mailing list