patternModeratepending
Pattern: Backend for Frontend (BFF) for multiple clients
Viewed 0 times
BFFbackend-for-frontendAPIclient-specificaggregation
Problem
Different clients (web, mobile, IoT) need different data shapes, aggregations, and protocols from the same backend services.
Solution
Create a dedicated backend per client type:
# Instead of one API serving all clients:
# Generic API -> Web, Mobile, Watch, TV
# Create dedicated BFFs:
# Web BFF -> Web app (full data, SSR support)
# Mobile BFF -> Mobile app (minimal data, offline support)
# Watch BFF -> Watch app (tiny payloads, push)
# Web BFF: optimized for web needs
@app.get('/web/dashboard')
async def web_dashboard(user_id: str):
# Aggregate from multiple services
user, orders, notifications = await asyncio.gather(
user_service.get(user_id),
order_service.recent(user_id, limit=20),
notification_service.unread(user_id),
)
# Return web-optimized shape
return {
'user': user,
'recent_orders': orders,
'notifications': notifications,
'sidebar_data': compute_sidebar(user),
}
# Mobile BFF: minimal payload
@app.get('/mobile/dashboard')
async def mobile_dashboard(user_id: str):
return {
'name': user.name,
'order_count': order_service.count(user_id),
'unread': notification_service.count(user_id),
}
Benefits:
# Instead of one API serving all clients:
# Generic API -> Web, Mobile, Watch, TV
# Create dedicated BFFs:
# Web BFF -> Web app (full data, SSR support)
# Mobile BFF -> Mobile app (minimal data, offline support)
# Watch BFF -> Watch app (tiny payloads, push)
# Web BFF: optimized for web needs
@app.get('/web/dashboard')
async def web_dashboard(user_id: str):
# Aggregate from multiple services
user, orders, notifications = await asyncio.gather(
user_service.get(user_id),
order_service.recent(user_id, limit=20),
notification_service.unread(user_id),
)
# Return web-optimized shape
return {
'user': user,
'recent_orders': orders,
'notifications': notifications,
'sidebar_data': compute_sidebar(user),
}
# Mobile BFF: minimal payload
@app.get('/mobile/dashboard')
async def mobile_dashboard(user_id: str):
return {
'name': user.name,
'order_count': order_service.count(user_id),
'unread': notification_service.count(user_id),
}
Benefits:
- Each client team owns their BFF
- No compromises between client needs
- Can evolve independently
- Simpler than a one-size-fits-all API
Why
Different clients have different needs. A shared API either over-fetches for simple clients or under-fetches for complex ones.
Revisions (0)
No revisions yet.