A polyglot microservices architecture for a food delivery platform, demonstrating service discovery, event-driven communication, API gateway pattern, and mixed technology stacks.
┌──────────────────────────────────────────┐
│ Client / Frontend │
└────────────────────┬─────────────────────┘
│
▼
┌──────────────────────────────────────────┐
│ API Gateway (:8080) │
│ Express + http-proxy-middleware │
└────┬──────────┬──────────┬───────────────┘
│ │ │
┌────────────┤ ┌───────┤ ┌───────┤
▼ ▼ ▼ ▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ User-service │ │Catalog-service│ │Basket-service │ │ Order-service│
│ (Node/MySQL) │ │(Node/MongoDB)│ │(Python/Redis)│ │(Node/Postgres│
│ :3001 │ │ :3002 │ │ :8000 │ │ :3003 │
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘
│ │ │ │
▼ ▼ ▼ │
┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ MySQL │ │ MongoDB │ │ Redis │ │
└──────────┘ └──────────┘ └──────────┘ │
│
┌──────▼───────┐
│ RabbitMQ │
│ :5672 │
└──────┬───────┘
│
▼
┌──────────────┐
│message-service│
│ (Node/AMQP) │
│ :3010 │
└──────────────┘
┌──────────────────────────────────────────┐
│ Netflix Eureka (:8761) │
│ Service Registry │
└──────────────────────────────────────────┘
The single entry point into the system. Routes incoming requests to the appropriate backend service by looking up service instances in Eureka.
| Attribute | Detail |
|---|---|
| Language | Node.js 20 |
| Framework | Express 4.x |
| Port | 8080 |
Route mapping:
| Gateway Path | Backend Service |
|---|---|
/api/users |
User Service |
/api/restaurant |
Catalog Service |
/api/basket |
Basket Service |
/api/orders |
Order Service |
Handles user registration, login, and profile management. Issues JWT tokens for authentication.
| Attribute | Detail |
|---|---|
| Language | Node.js 20 |
| Framework | Express 4.x |
| Database | MySQL 8.0 |
| Port | 3000 → host 3001 |
Features:
- User registration with email/password validation
- JWT-based login (8-hour expiry)
- Password hashing with bcrypt (10 salt rounds)
- Profile CRUD operations
- Token-protected routes
Manages the restaurant catalog. Each restaurant contains a list of menu items.
| Attribute | Detail |
|---|---|
| Language | Node.js 20 |
| Framework | Express 5.x |
| Database | MongoDB 6.0 (via Mongoose) |
| Port | 3000 → host 3002 |
Features:
- Full CRUD for restaurants
- Nested food items within each restaurant
- Search by restaurant ID or list all
Manages per-user shopping baskets. A lightweight service written in Python.
| Attribute | Detail |
|---|---|
| Language | Python 3.11 |
| Framework | FastAPI |
| Database | Redis 7 (Alpine) |
| Port | 8000 → host 8000 |
Features:
- Add items to a user's basket
- Update item quantities
- Remove individual items or clear the entire basket
- Redis key pattern:
basket:{user_id}:{item_id}
Manages the order lifecycle. Publishes events to RabbitMQ when orders are created.
| Attribute | Detail |
|---|---|
| Language | Node.js 20 |
| Framework | Express 4.x |
| Database | PostgreSQL 16 (Alpine) |
| Message Broker | RabbitMQ (publisher → order.events queue) |
| Port | 3000 → host 3003 |
Features:
- Full CRUD for orders (UUID primary key)
- Stores order items as JSONB
- Publishes
order.createdevent to RabbitMQ on order creation - Retries RabbitMQ connection up to 40 times
An event consumer that listens for order.created events and simulates sending confirmation emails.
| Attribute | Detail |
|---|---|
| Language | Node.js 20 (ES Modules) |
| Framework | Native http module (no Express) |
| Message Broker | RabbitMQ (consumer ← order.events queue) |
| Port | 3002 → host 3010 |
Features:
- Consumes
order.eventsqueue with manual acknowledgment - Simulates email sending (logs to console)
- Handles unknown event types gracefully
A lightweight alternative order publisher — creates orders and publishes events directly to RabbitMQ without a persistent database.
| Attribute | Detail |
|---|---|
| Language | Node.js 20 |
| Framework | Express 4.x |
| Message Broker | RabbitMQ (publisher → order.events queue) |
| Port | 3001 |
| Component | Image | Port(s) | Purpose |
|---|---|---|---|
| Eureka | dnl50/eureka-server:1.0.4 |
8761 |
Service registry & discovery |
| MySQL | mysql:8.0 |
internal | User data persistence |
| MongoDB | mongo:6.0 |
internal | Restaurant catalog persistence |
| Redis | redis:7-alpine |
internal | Basket data cache |
| PostgreSQL | postgres:16-alpine |
internal | Order data persistence |
| RabbitMQ | rabbitmq:3.13-management-alpine |
5672 (AMQP), 15672 (Management UI) |
Event messaging |
| Service | User | Password | Database |
|---|---|---|---|
| MySQL | appuser |
appsecret |
user_service |
| MongoDB | root |
example |
restaurants |
| PostgreSQL | orders |
orders_secret |
orders_db |
| RabbitMQ | foodapp |
foodapp_secret |
— |
Note: These are development credentials. Rotate them before any production deployment.
- Docker and Docker Compose v2+
- 8+ GB of free RAM recommended (all containers run concurrently)
# Clone the repository
git clone <repo-url> food-delivery-platform
cd food-delivery-platform
# Start all services
docker compose up -d
# Watch logs for a specific service
docker compose logs -f api-gateway
# Check service health
curl http://localhost:8080/api/users/health
curl http://localhost:8080/api/restaurant/health
curl http://localhost:8080/api/basket/health
curl http://localhost:8080/api/orders/health
# Stop everything
docker compose downWait ~30-60 seconds for all services to start and register with Eureka. The API Gateway retries Eureka lookups automatically.
# Register
curl -X POST http://localhost:8080/api/users/register \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","password":"password123","first_name":"John","last_name":"Doe"}'
# Login (returns JWT)
curl -X POST http://localhost:8080/api/users/login \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","password":"password123"}'
# Get profile (use token from login)
curl http://localhost:8080/api/users/profile \
-H "Authorization: Bearer <token>"# Create restaurant
curl -X POST http://localhost:8080/api/restaurant \
-H "Content-Type: application/json" \
-d '{"name":"Pizza Place","address":"123 Main St","rating":4.5}'
# Add food item
curl -X POST http://localhost:8080/api/restaurant/<id> \
-H "Content-Type: application/json" \
-d '{"name":"Margherita","description":"Classic pizza","price":12.99}'
# List all restaurants
curl http://localhost:8080/api/restaurant# Add item to basket
curl -X POST http://localhost:8080/api/basket/user123 \
-H "Content-Type: application/json" \
-d '{"item_id":"item1","name":"Margherita","description":"Classic pizza","price":12.99,"amount":2}'
# View basket
curl http://localhost:8080/api/basket/user123
# Clear basket
curl -X DELETE http://localhost:8080/api/basket/user123# Create order (triggers order.created event)
curl -X POST http://localhost:8080/api/orders \
-H "Content-Type: application/json" \
-d '{"userId":"user123","customerEmail":"user@example.com","items":[{"sku":"item1","qty":2}]}'
# List orders
curl http://localhost:8080/api/ordersAll application services register with Netflix Eureka on startup. The API Gateway uses Eureka to dynamically resolve service locations — it never hits a hardcoded hostname. If a service isn't found, the gateway retries 6 times before returning a 503.
When an order is created:
- Order Service persists the order in PostgreSQL
- Order Service publishes an
order.createdevent to theorder.eventsRabbitMQ queue - Message Service consumes the event and simulates sending a confirmation email
This decouples order creation from notification logic — the Order Service doesn't need to know about email delivery.
All external traffic goes through the API Gateway (:8080). This provides:
- Single entry point — clients don't need to know about internal topology
- Dynamic routing — backend services can scale or move without client changes
- Separation of concerns — cross-cutting logic (auth, rate limiting, logging) can be added at the gateway level
.
├── README.md
├── docker-compose.yml # Main orchestration
├── .gitignore
├── Gateway-service/ # API Gateway (Node/Express)
│ ├── dockerfile
│ ├── package.json
│ └── gateway/index.js
├── User-service/ # Auth & Profiles (Node/Express/MySQL)
│ ├── dockerfile
│ ├── package.json
│ └── server.js
├── Catalog-service/ # Restaurant Catalog (Node/Express/MongoDB)
│ ├── dockerfile
│ ├── package.json
│ └── server.js
├── Basket-service/ # Shopping Basket (Python/FastAPI/Redis)
│ ├── dockerfile
│ ├── main.py
│ └── requirements.txt
├── Order-service/ # Order Management (Node/Express/PostgreSQL)
│ ├── dockerfile
│ ├── package.json
│ └── server.js
└── RabbitMQ-service/ # Event consumers & publishers
├── message-service/ # Order event consumer (email simulation)
│ ├── dockerfile
│ ├── package.json
│ └── index.js
└── order-service/ # Standalone order publisher
├── dockerfile
├── package.json
└── index.js
| Service | Language | Framework | Database | Extras |
|---|---|---|---|---|
| API Gateway | Node.js | Express | — | Eureka client, http-proxy-middleware |
| User Service | Node.js | Express | MySQL | JWT, bcrypt |
| Catalog Service | Node.js | Express | MongoDB | Mongoose ODM |
| Basket Service | Python | FastAPI | Redis | py-eureka-client |
| Order Service | Node.js | Express | PostgreSQL | RabbitMQ publisher |
| Message Service | Node.js | — (native http) | — | RabbitMQ consumer |
| Standalone Publisher | Node.js | Express | — | RabbitMQ publisher |
Each service can be run independently for development. Refer to each service's dockerfile and package.json/requirements.txt for specific instructions. In general:
Node.js services:
cd <service-directory>
npm install
npm startPython service (Basket):
cd Basket-service
pip install -r requirements.txt
uvicorn main:app --port 8000You'll need to have the corresponding infrastructure services (databases, Eureka, RabbitMQ) running — use docker compose up -d eureka mysql mongo redis postgres rabbitmq to start just the infrastructure layer.
This project is for educational/demonstration purposes.