DEV Community

Cover image for Getting Started with gRPC in Python (With a Restaurant Twist πŸ•)
cycy
cycy

Posted on

Getting Started with gRPC in Python (With a Restaurant Twist πŸ•)

If you've ever wondered how different parts of an app talk to each other β€” or how microservices "call" each other behind the scenes β€” this one's for you.

In this post, I'll show you how to use gRPC in Python to build a menu service. We'll keep things light, use a kitchen/waiter analogy 🍽️, and write some real working code together.


πŸ”„ What's gRPC? (But Make It Restaurant-Themed)

Let's say you're at a restaurant:

  • Kitchen = the server (makes food)
  • Waiter = the client (asks for food)
  • Menu = the data structure (what's available)

The waiter goes, "Hey, what's on the menu today?"

The kitchen replies with delicious dishes.

This is literally what gRPC helps services do: ask for stuff, get a response β€” but way faster and stricter than REST.


πŸ› οΈ Prerequisites

First, let's install what we need:

pip install grpcio grpcio-tools
Enter fullscreen mode Exit fullscreen mode

πŸ“ Step 1: Define the Language (menu.proto)

We need a shared language both waiter and kitchen understand.

Create a file called menu.proto:

syntax = "proto3";

package menu;

import "google/protobuf/empty.proto";

service MenuService {
  rpc ListMenus (google.protobuf.Empty) returns (MenuList);
}

message Menu {
  string id = 1;
  string name = 2;
  string description = 3;
  double price = 4;
}

message MenuList {
  repeated Menu items = 1;
}
Enter fullscreen mode Exit fullscreen mode

βš™οΈ Step 2: Generate Python Code from the Proto

This turns your .proto file into real Python code.

Run this in terminal:

python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. menu.proto
Enter fullscreen mode Exit fullscreen mode

Boom πŸ’₯ β€” now you've got menu_pb2.py and menu_pb2_grpc.py.


πŸ§‘β€πŸ³ Step 3: Build the Server (Our Kitchen)

Create server.py:

import grpc
from concurrent import futures
from google.protobuf.empty_pb2 import Empty
import menu_pb2
import menu_pb2_grpc

class MenuService(menu_pb2_grpc.MenuServiceServicer):
    def ListMenus(self, request, context):
        return menu_pb2.MenuList(items=[
            menu_pb2.Menu(
                id="1", 
                name="Pizza Margherita", 
                description="Fresh tomatoes, mozzarella, basil", 
                price=12.99
            ),
            menu_pb2.Menu(
                id="2", 
                name="Classic Burger", 
                description="Beef patty, lettuce, tomato, cheese", 
                price=9.99
            ),
            menu_pb2.Menu(
                id="3", 
                name="Caesar Salad", 
                description="Crispy romaine, parmesan, croutons", 
                price=8.50
            ),
        ])

def serve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    menu_pb2_grpc.add_MenuServiceServicer_to_server(MenuService(), server)
    server.add_insecure_port("[::]:50051")
    server.start()
    print("🍽️ gRPC Server running on port 50051")
    server.wait_for_termination()

if __name__ == "__main__":
    serve()
Enter fullscreen mode Exit fullscreen mode

🧾 Step 4: Create the Client (Our Waiter)

Create client.py:

import grpc
from google.protobuf.empty_pb2 import Empty
import menu_pb2
import menu_pb2_grpc

def run():
    with grpc.insecure_channel("localhost:50051") as channel:
        stub = menu_pb2_grpc.MenuServiceStub(channel)

        try:
            response = stub.ListMenus(Empty())

            print("πŸ“‹ Today's Menu:")
            print("-" * 40)
            for item in response.items:
                print(f"🍽️  {item.name}")
                print(f"    {item.description}")
                print(f"    πŸ’° ${item.price:.2f}")
                print()

        except grpc.RpcError as e:
            print(f"❌ Error: {e}")

if __name__ == "__main__":
    run()
Enter fullscreen mode Exit fullscreen mode

πŸ§ͺ Step 5: Try It Out

  1. Run the server (in one terminal):
   python server.py
Enter fullscreen mode Exit fullscreen mode
  1. Run the client (in another terminal):
   python client.py
Enter fullscreen mode Exit fullscreen mode

You should see something like:

πŸ“‹ Today's Menu:
----------------------------------------
🍽️  Pizza Margherita
    Fresh tomatoes, mozzarella, basil
    πŸ’° $12.99

🍽️  Classic Burger
    Beef patty, lettuce, tomato, cheese
    πŸ’° $9.99

🍽️  Caesar Salad
    Crispy romaine, parmesan, croutons
    πŸ’° $8.50
Enter fullscreen mode Exit fullscreen mode

Yesss πŸ™Œ it's working!


🧠 What's Actually Happening?

+-----------+        ask for menu       +-----------+
|  Client   |  ---------------------->  |  Server   |
| (Waiter)  |                          | (Kitchen) |
|           |  <----------------------  |           |
|           |      send back menu      |           |
+-----------+                          +-----------+

Enter fullscreen mode Exit fullscreen mode

The waiter (client) asks for the menu using a specific method call. The kitchen (server) replies with a structured list of menu items. No JSON parsing, no HTTP overhead β€” just pure, efficient communication.


πŸ€” Why Use gRPC Instead of REST?

Feature REST gRPC
Format JSON (text) Protocol Buffers (binary)
Speed Good ⚑ Faster!
Type Safety Runtime errors Compile-time checks πŸ›‘οΈ
Streaming Limited Bidirectional streams 🌊
Tooling Manual setup Auto-generated stubs πŸͺ„
Best For Public APIs, web Microservices, internal

πŸš€ Level Up: Add Error Handling

Want to make it production-ready? Here's how to add proper error handling to your server:

def ListMenus(self, request, context):
    try:
        # Simulate potential database call
        menus = self._get_menus_from_database()
        return menu_pb2.MenuList(items=menus)
    except Exception as e:
        context.set_code(grpc.StatusCode.INTERNAL)
        context.set_details(f"Failed to fetch menus: {str(e)}")
        return menu_pb2.MenuList()

def _get_menus_from_database(self):
    # Your database logic here
    return [
        menu_pb2.Menu(id="1", name="Pizza", description="Yummy", price=12.99)
    ]
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ Quick Wins & Tips

File Structure:

your-project/
β”œβ”€β”€ menu.proto
β”œβ”€β”€ server.py
β”œβ”€β”€ client.py
β”œβ”€β”€ menu_pb2.py (generated)
└── menu_pb2_grpc.py (generated)
Enter fullscreen mode Exit fullscreen mode

Pro Tips:

  • Always use with grpc.insecure_channel() for proper connection cleanup
  • Add proper logging with Python's logging module
  • Use virtual environments: python -m venv grpc-env
  • For production, use secure channels with TLS

🎯 What's Next?

Now that you've got the basics down, here are some fun directions to explore:

  • Add CRUD operations (Create, Update, Delete menu items)
  • Connect to a real database (PostgreSQL, MongoDB)
  • Add authentication with JWT tokens
  • Implement streaming for real-time updates
  • Deploy with Docker for easy distribution

πŸ’¬ Wanna Go Deeper?

Let me know in the comments if you want tutorials on:

  • πŸ”’ Securing gRPC APIs with authentication
  • 🐘 gRPC + PostgreSQL integration
  • 🌊 Streaming with gRPC (real-time data)
  • 🐳 Dockerizing gRPC services
  • πŸ”„ gRPC + REST gateway (best of both worlds)

πŸ™‹ Got Questions?

Drop them below β€” I love helping fellow devs learn backend stuff! Or tag me if you build something cool with gRPC!

Found this helpful? Give it a ❀️ and follow for more beginner-friendly backend tutorials πŸ˜„


Happy coding! πŸš€

Top comments (0)