My Next API — gRPC | RESTful

REST — The default choice

gRPC

Differences between gRPC and REST

Payload

Transfer Protocol

Conceptual Model

Where to use gRPC

  1. Microservices: gRPC shines as a way to connect servers in service-oriented environments.
  2. Client-Server Applications: gRPC works just as well in client-server applications, where the client application runs on a desktop or mobile devices using HTTP/2 which improves the latency and network utilization.
  3. Integrations and APIs: gRPC is also a way to offer APIs over the internet for integrating applications with services from third-party providers.
  4. Real-time streaming: When real-time communication is a requirement, gRPC’s ability to manage bidirectional streaming allows your system to send and receive messages in real-time without waiting for Unary client-response communication.
  5. Low-power low-bandwidth networks: gRPC’s use of serialized Protobuf messages offers light-weight messaging, greater efficiency, and speed for bandwidth-constrained, low-power networks.

Practice Time — Example Project

grpc-python-example
├── client.py
├── definitions
│ ├── builds
│ │ ├── __init__.py
│ │ ├── service_pb2_grpc.py
│ │ └── service_pb2.py
│ ├── __init__.py
│ └── service.proto
├── README.md
├── requirements.txt
├── server.py
└── test.py
mkdir grpc-python-example
cd
grpc-python-example
virtualenv --python=python3.8 .venv
source .venv/bin/activate
pip install --upgrade pip
pip install grpcio grpcio-tools googleapis-common-protos
mkdir definitions
touch service.proto
// service.protosyntax = "proto3";

message Null {}

message Ticket {
string name = 1;
string description = 2;
uint32 story_points = 3;
}

message Confirmation {
string expected_dateline = 1;
}

service TestService {
rpc Health(Null) returns (Null);
rpc AddTicket(Ticket) returns (Confirmation);
}
python -m grpc_tools.protoc -I definitions/ --python_out=definitions/builds/ --grpc_python_out=definitions/builds/ definitions/service.proto
# server.py
# -*- coding: utf-8 -*-

from concurrent.futures import ThreadPoolExecutor
from datetime import datetime, timedelta

import grpc

from definitions.builds.service_pb2 import Confirmation
from definitions.builds.service_pb2_grpc import TestServiceServicer, add_TestServiceServicer_to_server


class Service(TestServiceServicer):
def Health(self, request, context):
return request

def AddTicket(self, request, context):
expected_dateline = datetime.utcnow() + timedelta(days=request.story_points)
return Confirmation(expected_dateline=expected_dateline.strftime("%Y-%m-%d %H:%M:%S"))

def execute_server():
server = grpc.server(ThreadPoolExecutor(max_workers=10))
add_TestServiceServicer_to_server(Service(), server)
server.add_insecure_port("[::]:3000")
server.start()

print("The server is up and running...")
server.wait_for_termination()


if __name__ == "__main__":
execute_server()
# client.py
# -*- coding: utf-8 -*-

import grpc

from definitions.builds.service_pb2 import Null, Ticket
from definitions.builds.service_pb2_grpc import TestServiceStub


def main():
with grpc.insecure_channel("localhost:3000") as channel:
client = TestServiceStub(channel)
client.Health(Null())

confirmation = client.AddTicket(Ticket(
name="SomeTicket",
description="...",
story_points=2
))

print(confirmation.expected_dateline)


if __name__ == "__main__":
main()

Performance Comparison

# For gRPC...
# -*- coding: utf-8 -*-

from time import time

import grpc

from definitions.builds.service_pb2 import Null, Ticket
from definitions.builds.service_pb2_grpc import TestServiceStub


def main():
with grpc.insecure_channel("localhost:3000") as channel:
client = TestServiceStub(channel)
client.Health(Null())
start = time()

for _ in range(2000):
client.AddTicket(Ticket(
name="SomeTicket",
description="...",
story_points=2
))

print(time() - start)


if __name__ == "__main__":
main()
# fastapi_server.py
# -*- coding: utf-8 -*-

import json
from datetime import datetime, timedelta

import uvicorn
from fastapi import FastAPI
from starlette.requests import Request

app = FastAPI()


@app.get("/health")
def health():
return {"Hello": "World"}


@app.post("/ticket")
async def manage_tickets(request: Request,):
points = json.loads(await request.body()).get("story_points")
expected_dateline = datetime.utcnow() + timedelta(days=points)
return expected_dateline.strftime("%Y-%m-%d %H:%M:%S")


if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=3001)
# flask_server.py
# -*- coding: utf-8 -*-

import json
from datetime import datetime, timedelta

from flask import Flask
from flask import request

app = Flask(__name__)


@app.route("/")
def health():
return "OK"


@app.route("/ticket", methods=["POST"])
def manage_tickets():
points = json.loads(request.data).get("story_points")
expected_dateline = datetime.utcnow() + timedelta(days=points)
return expected_dateline.strftime("%Y-%m-%d %H:%M:%S")


if __name__ == "__main__":
app.run(port=3001)
python flask_server.py
python fastapi_server.py
# test.py
# -*- coding: utf-8 -*-

import json
from time import time

import urllib3

http = urllib3.PoolManager()


def main():
start = time()

for _ in range(2000):
http.request(
"POST",
"http://localhost:3001/ticket",
headers={"Content-Type": "application/json"},
body=json.dumps({
"name": "x",
"description": "...",
"story_points": 3
})
)

print(time() - start)


if __name__ == "__main__":
main()

Results…

FastAPI                 Flask                   gRPC
2.5365726947784424 3.588320016860962 0.6878361701965332
2.4663445949554443 3.4863481521606445 0.7431104183197021
2.8214125633239746 3.522181749343872 0.719865083694458

Conclusions

--

--

--

Cloud & Solutions & Data Architect | Python Developer | Serverless Advocate

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

100 Days of VR: Day 15 Adding Shooting, Hit, and More Walking Sound Effects!

2017 Document Management Software Comparison: eFileCabinet vs Pinpoint

Our way of migrating from RxJava to Kotlin Coroutines

10 Best Wireless Access Points in 2022

Ubiquiti Wave2

Blue-Green Deployment with dbt and Snowflake

How to Embed Video in WordPress?

How to Embed Video in WordPress?

Explainers: Instrumenting your service

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Alejandro Cora González

Alejandro Cora González

Cloud & Solutions & Data Architect | Python Developer | Serverless Advocate

More from Medium

Build CRUD Operations with Node JS and Python on DataStax Astra DB

Relational Database working in 5 minutes

Deploying a Scalable SQL Cluster on Kubernetes

Poll batches of Kafka messages with confluent-kafka-python with ThreadPoolExecutor