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)