A hands-on example of 5 Python microservices communicating over REST, with full CRUD operations and SQLite persistence.
| Service | Port | Responsibility |
|---|---|---|
| Gateway | 8000 | Single entry point — routes all requests to the correct service |
| Users | 8001 | Create and manage user accounts |
| Products | 8002 | Create and manage the product catalog |
| Inventory | 8003 | Track stock levels per product |
| Orders | 8004 | Place orders — calls Users, Products, and Inventory internally |
Each service is its own container with its own SQLite database file (/data/*.db) mounted from a named Docker volume.
Client
│
▼
Gateway :8000 ← only port exposed publicly
│
├── /users/* → Users Service :8001 (users.db)
├── /products/* → Products Service :8002 (products.db)
├── /inventory/* → Inventory Service :8003 (inventory.db)
└── /orders/* → Orders Service :8004 (orders.db)
│
├── calls Users (validate user exists)
├── calls Products (get name + price)
└── calls Inventory (reserve stock)
When you POST /orders, the Orders service makes HTTP calls to the other three services before writing the order — this is the cross-service communication pattern the workshop demonstrates.
docker-compose up --buildServices start in dependency order enforced by health checks:
- Users, Products, Inventory start in parallel
- Orders starts once all three are healthy
- Gateway starts once Orders is healthy
Data persists across restarts via named Docker volumes. To wipe all data:
docker-compose down -vpip install -r requirements.txt
./start-local.shWith services running, execute the demo script to walk through the full flow:
./demo.shThis will:
- Create a user
- Create a product
- Add inventory for that product
- Place an order (triggers cross-service calls)
- Verify stock was decremented
- List all orders
Every service exposes a Swagger UI at /docs:
- http://localhost:8000/docs — Gateway
- http://localhost:8001/docs — Users
- http://localhost:8002/docs — Products
- http://localhost:8003/docs — Inventory
- http://localhost:8004/docs — Orders
# Create a user
curl -X POST http://localhost:8000/users \
-H "Content-Type: application/json" \
-d '{"name": "Alice", "email": "alice@example.com"}'
# Create a product
curl -X POST http://localhost:8000/products \
-H "Content-Type: application/json" \
-d '{"name": "Laptop", "description": "Dev machine", "price": 1299.99}'
# Add inventory
curl -X POST http://localhost:8000/inventory \
-H "Content-Type: application/json" \
-d '{"product_id": "<product-id>", "quantity": 50, "location": "Warehouse A"}'
# Place an order
curl -X POST http://localhost:8000/orders \
-H "Content-Type: application/json" \
-d '{"user_id": "<user-id>", "product_id": "<product-id>", "quantity": 2}'workshop-python-microservices/
├── docker-compose.yml
├── requirements.txt
├── start-local.sh # run all services locally
├── demo.sh # end-to-end walkthrough script
├── gateway/
│ ├── Dockerfile
│ └── main.py
├── users-service/
│ ├── Dockerfile
│ └── main.py
├── products-service/
│ ├── Dockerfile
│ └── main.py
├── inventory-service/
│ ├── Dockerfile
│ └── main.py
└── orders-service/
├── Dockerfile
└── main.py
- FastAPI — REST framework with automatic Swagger UI
- Uvicorn — ASGI server
- SQLite — embedded database, one file per service
- httpx — HTTP client for cross-service calls
- Docker Compose — local orchestration with health checks and named volumes