gRPC Tutorial
gRPC (Remote Procedure Calls) is an open source remote procedure call (RPC) system initially developed at Google. It uses HTTP/2 for transport, Protocol Buffers as the interface description language, and provides features such as authentication, bidirectional streaming and flow control, blocking or nonblocking bindings, and cancellation and timeouts. It generates cross-platform client and server bindings for many languages. Most common usage scenarios includes connecting services in microservices style architecture and connect mobile devices, browser clients to backend services

Getting Started with gRPC
The workflow to create a gRPC service is simple:
- Create the service definition and payload structure in the Protocol Buffer (.proto) file.
- Generate the gRPC code from the .proto file using proto compiler.
- Implement the server in one of the supported languages.
- Create the client that invokes the service through the Stub.
- Run the server and client(s).
Set up Environment for gRPC
Configure Python
python -m pip install virtualenv
virtualenv venv
source venv/bin/activate
python -m pip install --upgrade pip
Install gRPC and gRPC Tools
python -m pip install grpcio
python -m pip install grpcio-tools
npm install grpc --global
Create the directories for the Protocol Buffer, Server, and Client
mkdir Proto
mkdir Server
mkdir -p Client/Python
Create the Protocol Buffer (Proto/Calc.proto) in the Proto directory
syntax = "proto3";
package calc;
service Calculator {
rpc Add (AddRequest) returns (AddReply) {}
rpc Substract (SubstractRequest) returns (SubstractReply) {}
rpc Multiply (MultiplyRequest) returns (MultiplyReply) {}
rpc Divide (DivideRequest) returns (DivideReply) {}
rpc SquareRoot (SquareRootRequest) returns (SquareRootReply) {}
}
message SquareRootRequest {
float n1= 1;
}
message SquareRootReply {
float n1= 1;
}
message AddRequest{
int32 n1=1;
int32 n2=2;
}
message AddReply{
int32 n1=1;
}
message SubstractRequest{
int32 n1=1;
int32 n2=2;
}
message SubstractReply{
int32 n1=1;
}
message MultiplyRequest{
int32 n1=1;
int32 n2=2;
}
message MultiplyReply{
int32 n1=1;
}
message DivideRequest{
int32 n1=1;
int32 n2=2;
}
message DivideReply{
float f1=1;
}
Generate Python client and server code and copy it to the directories
python -m grpc.tools.protoc --python_out=. --grpc_python_out=. --proto_path=. Calc.proto
cp Calc_pb2.py Calc_pb2_grpc.py ../Server
cp Calc_pb2.py Calc_pb2_grpc.py ../Client/Python
Create the Server (Server/Calc_Server.py)
from concurrent import futures
import time
import grpc
import math
import Calc_pb2
import Calc_pb2_grpc
_ONE_DAY_IN_SECONDS = 60 * 60 * 24
class Calculator(Calc_pb2_grpc.CalculatorServicer):
def Add(self, request, context):
return Calc_pb2.AddReply(n1=request.n1+request.n2)
def Substract(self, request, context):
return Calc_pb2.SubstractReply(n1=request.n1-request.n2)
def Multiply(self, request, context):
return Calc_pb2.MultiplyReply(n1=request.n1*request.n2)
def Divide(self, request, context):
return Calc_pb2.DivideReply(f1=request.n1/request.n2)
def SquareRoot(self, request, context):return Calc_pb2.SquareRootReply(y = math.sqrt(request.n1))
def serve():
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
Calc_pb2_grpc.add_CalculatorServicer_to_server(Calculator(), server)
server.add_insecure_port('[::]:50050')
server.start()
try:
while True:
time.sleep(_ONE_DAY_IN_SECONDS)
except KeyboardInterrupt:
server.stop(0)
if __name__ == '__main__':
serve()
Launch the Server
python Calc_Server.py
Create the Python Client (Client/Python/Calc_Client.py)
from __future__ import print_function
import grpc
import Calc_pb2
import Calc_pb2_grpc
def run():
channel = grpc.insecure_channel('localhost:50050')
stub = Calc_pb2_grpc.CalculatorStub(channel)
response = stub.Add(Calc_pb2.AddRequest(n1=50,n2=50))
print("Addition = " + str(response.n1))
response = stub.Substract(Calc_pb2.SubstractRequest(n1=200,n2=10))
print("Substraction = " + str(response.n1))
response = stub.Multiply(Calc_pb2.MultiplyRequest(n1=10,n2=10))
print("Multiplication = " + str(response.n1))
response = stub.Divide(Calc_pb2.DivideRequest(n1=200,n2=10))
print("Devide = " + str(response.f1))
response = stub.SquareRoot(Calc_pb2.SquareRootRequest(n1=100))
print("SquareRoot = " + str(response.y))
if __name__ == '__main__':
run()
Launch the Python Client
python Calc_Client.py
#output
Addition = 100
Substraction = 190
Multiplication = 100
Devide = 20
SquareRoot = 10
Reference
https://thenewstack.io/grpc-lean-mean-communication-protocol-microservices
https://engineering.semantics3.com/a-simplified-guide-to-grpc-in-python-6c4e25f0c506