Unary API with gRPC
What is gRPC ?
gRPC stands for google Remote Procedure Call and it is the technology that will invetably lead the future of API designing and communication
What does RPC mean
RPC stands for Remote Procedure Call and it simply defines the *procedure for calling a function on the server from the client .
Why should you care
Well, it's basically 5 things that gRPC offers out of the box
- Speed => as it is transmitted through multiplexing/ over HTTP2 ([Link to blog](http://))
- Security => As HTTP2 compulsarily implements SSL
- Developer Ease => gRPC is language agnostic so you could literally talk to a python server from a react client, have a C++ proxy in the middle and handle yor database in Java without the heavy lifting of serializing communication objects
- Request
- Response
- Service (The function that will take in request and return a response)
- sum_pb ⇒ Contains all the details about the request and response object whereas the
- sum_grpc_pb ⇒ Will help the grpc server create an API from the proto generated code.
- sum_grpc_pb ⇒ Contains proto generated code that will help us setup the client and link it to the server functions we have defined
- sum_pb ⇒ Contains code to help us access and work with the request object
There are several more of such features that gRPC hands out of the box for API management
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/
| |-- max.proto
|-- server/
|-- index.js
|-- protos/
|-- max_pb.js
|-- max_grpc_pb.js
0. Sample Problem
In this exercise, we will be building a Calculate the sum of numbers sent from client to server.
The function takes a Request message that has 2 integers, and returns a single Response that represents the sum of these numbers.
1. Make the protofile
This just involves creation of 3 things
syntax="proto3";
package PACKAGENAME;
message SumMessage{
int32 first_num = 1;
int32 second_num = 2;
}
message SumRequest{
SumMessage sum_message = 1;
}
message SumResponse{
int32 result = 1;
}
service SumService{
rpc Sum(SumRequest) returns (SumResponse){}
}
Here, SumRequest and SumResponse are the request response objects and SumMessage just helps describe the request object
2. Generate the protofiles
Packages required : protoc, grpc-tools
1. grpc-tools
npm i grpc-tools
We get SumServiceService and SumServiceClient 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/sum.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,
const grpc = require("grpc")
const sumService = require('./protos/sum_grpc_pb')
const sums = require('./protos/sum_pb')
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
const sum = (call, callback) =>
// The name is chosen as "sum" as in the proto we have said, in PascalCasing that the "Sum" function will take in a request and return a response
{
const summing = new sums.SumResponse()
summing.setResult(
call.request.getSumMessage().getFirstNum()
+ call.request.getSumMessage().getSecondNum()
)
callback(null,summing)
}
Start up the gRPC server and link it to our function and proto generated code
const server = new grpc.Server()
server.addService(sumService.SumServiceService,{sum})
const url = "127.0.0.1:50051"
server.bind(url, grpc.ServerCredentials.createInsecure())
server.start()
4. Setup the Client Side
Import the necessary dependencies.
const grpc = require('grpc');
const sumService = require('../server/protos/sum_grpc_pb')
const sums = require('../server/protos/sum_pb')
Setup a client using the proto generated code
const sumClient = new sumService.SumServiceClient(
'localhost:50051',
grpc.credentials.createInsecure()
)
Configure and send the request object
const sumRequest = new sums.SumRequest()
const sumObject = new sums.SumMessage()
sumObject.setFirstNum(3)
sumObject.setSecondNum(10)
sumRequest.setSumMessage(sumObject)
Handle the response received on the client side
sumClient.sum(sumRequest, (error, response) =>
{
if (!error)
{
console.log(`Sum result : ${response.getResult()}`)
} else
{
console.log(error)
}
})
Add service to server and start it
//* Setup a server
const server = new grpc.Server()
server.addService(sumService.SumServiceService, { sum })
//? 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 bidirectional streaming type API designing. Thanks a lot for reading this blog. If you like more content like this, subscribe to my mailing list
Conclusion
Congratulations ! You are now equipped with the futuristic skills of API designing. Thanks a lot for reading this blog. If you like more content like this, subscribe to my mailing list