ecommerce-order-api/
│
├── src/ # Source code
│ ├── core/ # Cloud-agnostic business logic
│ │ └── order_service.py # OrderService class (main business logic)
│ │
│ └── handlers/ # Cloud provider-specific handlers
│ ├── aws_lambda_handler.py # AWS Lambda handler
│ ├── azure_function_handler.py # Azure Functions handler
│ └── gcp_function_handler.py # GCP Cloud Functions handler
│
├── tests/ # Unit tests
│ └── test_order_service.py # Tests for core service
│
├── database/ # Database scripts
│ └── schema.sql # PostgreSQL schema
│
├── aws/ # AWS-specific deployment files
│ └── template.yaml # SAM template
│
├── scripts/ # Deployment and utility scripts
│ └── deploy_aws.sh # AWS deployment script
│
├── requirements.txt # Python dependencies
├── .env.example # Environment variables template
├── test_order.json # Sample order data for testing
└── README.md # Documentation
The src/core/ directory contains business logic that works identically across all cloud providers:
- order_service.py: Contains the
OrderServiceclass with all order management logiccreate_order(): Creates new orders with validationget_order(): Retrieves orders with tenant isolationlist_orders(): Lists orders with pagination- Database operations
- Data validation
The src/handlers/ directory contains thin wrapper handlers for each cloud provider:
-
aws_lambda_handler.py: AWS Lambda-specific code
- Extracts Cognito claims from API Gateway event
- Formats responses for API Gateway
- Routes HTTP methods to core service
-
azure_function_handler.py: Azure Functions-specific code
- Extracts Azure AD claims
- Uses Flask-style request/response
- Routes to core service
-
gcp_function_handler.py: GCP Cloud Functions-specific code
- Extracts Firebase/Identity Platform claims
- Uses functions-framework
- Routes to core service
- Easy Migration: Change only the handler, core logic stays the same
- Testing: Test business logic independently of cloud provider
- Consistency: Same behavior across all cloud providers
- Maintenance: Update business logic once, works everywhere
- Multi-cloud: Deploy to multiple clouds simultaneously
Request
↓
API Gateway / Azure Functions / GCP HTTP
↓
Cloud-Specific Handler
- Extract auth claims
- Parse request
↓
OrderService (Core Logic)
- Validate data
- Execute business rules
- Database operations
↓
PostgreSQL Database
↓
Response
- Format for cloud provider
- Return to client
The OrderService receives database configuration, making it testable and flexible:
db_config = get_db_config() # Handler-specific
order_service = OrderService(db_config) # Cloud-agnosticEvery operation includes tenant_id for multi-tenant security:
order = order_service.create_order(
tenant_id='tenant-123', # From auth claims
user_id='user-456',
order_data=data
)Consistent error handling across all handlers:
- Validation errors → 400 Bad Request
- Not found → 404
- Server errors → 500
- Unit Tests: Test
OrderServicewith mocked database - Integration Tests: Test handlers with test database
- E2E Tests: Test deployed API with real requests
- All queries filtered by
tenant_id - Compound indexes:
(tenant_id, created_by),(tenant_id, order_id) - Row-level security (optional, can be added)
created_by: User who created the ordercreated_by_email: Email for audit purposescreated_at,updated_at: Timestamp tracking
- Foreign keys with CASCADE delete
- CHECK constraints on status and quantities
- NOT NULL constraints on required fields
- Authentication: Handled by cloud provider's gateway
- Authorization: Tenant isolation in all queries
- SQL Injection: Parameterized queries via psycopg2
- Secrets: Never hardcode, use provider secret managers
- HTTPS: Enforced by API Gateway/Functions
- Indexes: Strategic indexes on frequently queried columns
- Connection Management: Reuse connections when possible
- Pagination: Limit results to prevent large payloads
- Caching: Add Redis/ElastiCache for read-heavy workloads
To add new endpoints:
- Add method to
OrderService(core logic) - Add route handler in each cloud handler
- Update tests
- Update API documentation
Example - Add update order:
# In order_service.py
def update_order(self, order_id, tenant_id, updates):
# Core logic here
pass
# In aws_lambda_handler.py
def handle_update_order(path_parameters, body, order_service, auth_claims):
order = order_service.update_order(
order_id=path_parameters['order_id'],
tenant_id=auth_claims['tenant_id'],
updates=body
)
return create_response(200, {'order': order})Each cloud provider has built-in monitoring:
- AWS: CloudWatch Logs and Metrics
- Azure: Application Insights
- GCP: Cloud Logging and Monitoring
Add structured logging:
import logging
logger = logging.getLogger(__name__)
logger.info('Order created', extra={
'order_id': order_id,
'tenant_id': tenant_id,
'amount': total_amount
})