Skip to main content

gRPC in Python Example

· 7 min read
Serhii Hrekov
software engineer, creator, artist, programmer, projects founder

gRPC in Python: A Practical Example and When to Choose It​

gRPC (gRPC Remote Procedure Calls) is a modern, high-performance, open-source framework developed by Google that enables communication between services. It relies on Protocol Buffers (protobuf) for its Interface Definition Language (IDL) and uses HTTP/2 for transport.

It has become the standard choice for communication in microservices and polyglot (multi-language) environments where performance, efficiency, and strong typing are critical.

1. Why Choose gRPC over REST?​

While REST (using JSON over HTTP/1.1) is the universal standard for client-browser communication, gRPC offers significant advantages for server-to-server communication:

FeaturegRPC (Protocol Buffers, HTTP/2)REST (JSON, HTTP/1.1)
Data FormatBinary Protocol BuffersText-based JSON
PerformanceHigh. Faster serialization/deserialization, smaller payload size.Lower. Text parsing is CPU-intensive.
TransportHTTP/2. Supports multiplexing, header compression, and bi-directional streaming.HTTP/1.1 (often). New connection per request.
API ContractStrongly Typed. Defined strictly by .proto files.Weakly Typed. Rely on documentation/runtime checks.
Code GenerationAutomatic. Stubs and data classes are generated for all supported languages.Manual client implementation required.

2. When to Use gRPC​

gRPC is the right choice when your application meets one or more of these criteria:

  • Microservices Communication: The primary use case. Provides robust, low-latency communication between services written in different languages (Python, Go, Java, etc.).
  • High Performance and Low Latency: For systems like trading platforms, IoT data ingestion, or internal logging pipelines where every millisecond and byte matters.
  • Streaming Requirements: When you need bi-directional streaming (e.g., live chat, real-time data feeds), which HTTP/2 handles natively.
  • Polyglot Environments: When your front-end might be Node.js and your backend is Python—gRPC guarantees consistent, type-safe API contracts across all languages.

3. gRPC Example: Defining the Service​

We'll create a simple Greeting Service where the client sends a name and the server returns a customized greeting.

Step 1: Define the Service (.proto File)​

The API contract is defined using Protocol Buffers. This file is language-agnostic.

// greeter.proto
syntax = "proto3";

// Defines the service contract
service Greeter {
// A simple unary RPC (request-response)
rpc SayHello (HelloRequest) returns (HelloReply);
}

// Defines the message structure for the request
message HelloRequest {
string name = 1; // field number 1
}

// Defines the message structure for the response
message HelloReply {
string message = 1;
}

Step 2: Generate Python Code​

You use the protoc compiler and the gRPC Python plugin to generate Python source files (_pb2.py for messages and _pb2_grpc.py for service interfaces) from the .proto file.

# Assuming you have the protobuf compiler installed
# This command generates the required Python files
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. greeter.proto

4. gRPC Example: Server Implementation​

The server implements the business logic defined in the .proto file by inheriting from the generated service base class.

# greeter_server.py
import grpc
import time
from concurrent import futures
# Import the generated modules
import greeter_pb2
import greeter_pb2_grpc

# 1. Implementation of the Service
class GreeterServicer(greeter_pb2_grpc.GreeterServicer):

# Implements the rpc SayHello method
def SayHello(self, request, context):
# The 'request' object is a generated Python class (greeter_pb2.HelloRequest)
print(f"Server received request for: {request.name}")

# Create and return the response object
return greeter_pb2.HelloReply(
message=f"Hello, {request.name}! Welcome to gRPC."
)

# 2. Start the Server
def serve():
# Create a gRPC server running on a thread pool
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))

# Add the implemented service to the server
greeter_pb2_grpc.add_GreeterServicer_to_server(GreeterServicer(), server)

# Bind to a port
server.add_insecure_port('[::]:50051')
server.start()
print("gRPC Server started on port 50051.")

try:
# Keep the main thread alive to serve requests
while True:
time.sleep(86400) # Sleep for one day
except KeyboardInterrupt:
server.stop(0)

if __name__ == '__main__':
serve()

5. gRPC Example: Client Implementation​

The client uses the generated stubs to make high-performance calls as if they were local functions.

# greeter_client.py
import grpc
import greeter_pb2
import greeter_pb2_grpc

def run():
# 1. Establish a channel to the server
with grpc.insecure_channel('localhost:50051') as channel:

# 2. Create a stub (local client proxy) using the channel
stub = greeter_pb2_grpc.GreeterStub(channel)

# 3. Call the remote procedure (SayHello) as a local function
# The request is a generated Python class (greeter_pb2.HelloRequest)
try:
response = stub.SayHello(greeter_pb2.HelloRequest(name='Python Dev'))
print(f"Client received response: {response.message}")

except grpc.RpcError as e:
# Handle gRPC-specific errors (e.g., UNAVAILABLE, DEADLINE_EXCEEDED)
print(f"gRPC call failed: {e.details()}")

if __name__ == '__main__':
run()

Client Output:

Client received response: Hello, Python Dev! Welcome to gRPC.

Sources and Further Reading​

  1. gRPC Documentation - Official Python Quickstart
  2. Protocol Buffers Documentation - Developer Guide
  3. gRPC Documentation - Concepts (Explaining Streams and HTTP/2)
  4. Real Python - gRPC Tutorial (In-depth code walkthrough)