Back to list
seanchatmangpt

bff-patterns

by seanchatmangpt

The Agile Protocol Specification (APS), provides a comprehensive suite of tools, documentation, CLIs, platforms, and resources to support the implementation and evolution of agile practices across organizations. This repository serves as the definitive source for APS standards, best practices, and an ecosystem for agile development.

3🍴 0📅 Dec 28, 2025

SKILL.md


name: bff-patterns description: | Backend-for-Frontend architecture patterns for API aggregation, data transformation, and client-specific optimization. Activates when designing API layers between backends and frontends or implementing data transformation pipelines. allowed-tools:

  • Read
  • Write
  • Edit
  • Glob
  • Grep

Backend-for-Frontend (BFF) Patterns Skill

This skill implements BFF architecture patterns for creating optimized API layers between backends and frontend clients.

When This Skill Activates

  • Designing API aggregation layers
  • Creating client-specific backends
  • Implementing data transformation pipelines
  • Optimizing frontend-backend communication
  • Building GraphQL or REST façades

BFF Decision Framework

When to Use BFF

Answer these questions to determine if BFF is appropriate:

  1. Multiple Clients? Do you have web, mobile, and/or desktop clients with different data needs?
  2. Complex Aggregation? Does the frontend need to combine data from multiple services?
  3. Performance Critical? Is reducing round-trips and payload size important?
  4. Client Optimization? Do different clients need different data shapes?
  5. Security Boundary? Do you need to filter sensitive data before reaching clients?

If 3+ answers are "yes", BFF is recommended.

Core Patterns

1. API Aggregation Pattern

Client Request
     ↓
   [BFF]
   ↙   ↘
Service A  Service B
   ↘   ↙
 Aggregated Response
     ↓
   Client
// BFF aggregation example
async function getUserDashboard(userId: string) {
  const [user, orders, recommendations] = await Promise.all([
    userService.getUser(userId),
    orderService.getRecentOrders(userId),
    recommendationService.getForUser(userId)
  ]);

  return {
    profile: transformUserProfile(user),
    recentOrders: orders.slice(0, 5),
    topRecommendations: recommendations.slice(0, 3)
  };
}

2. Data Transformation Pattern

transformation:
  input: Raw backend response
  operations:
    - filter: Remove sensitive fields
    - map: Rename fields for client conventions
    - reduce: Aggregate related data
    - enrich: Add computed fields
  output: Client-optimized payload
// Transform backend user to mobile-friendly format
function transformForMobile(backendUser: BackendUser): MobileUser {
  return {
    id: backendUser.userId,
    displayName: `${backendUser.firstName} ${backendUser.lastName}`,
    avatar: backendUser.profileImageUrl || DEFAULT_AVATAR,
    // Omit sensitive fields like SSN, internal IDs
  };
}

3. Client-Specific BFF Pattern

           ┌─────────────┐
Web App ───│  Web BFF    │───┐
           └─────────────┘   │
           ┌─────────────┐   │   ┌──────────────┐
Mobile ────│ Mobile BFF  │───┼───│ Microservices│
           └─────────────┘   │   └──────────────┘
           ┌─────────────┐   │
IoT ───────│  IoT BFF    │───┘
           └─────────────┘

4. Caching Strategy Pattern

caching:
  levels:
    - level: Request
      strategy: Deduplication within request
      ttl: 0

    - level: Session
      strategy: User-specific cache
      ttl: 5m

    - level: Shared
      strategy: Common data cache
      ttl: 1h

    - level: Static
      strategy: Reference data
      ttl: 24h

5. Error Handling Pattern

// Graceful degradation in BFF
async function getDashboard(userId: string) {
  const results = await Promise.allSettled([
    userService.getUser(userId),
    orderService.getOrders(userId),
    recommendationService.get(userId)
  ]);

  return {
    user: results[0].status === 'fulfilled' ? results[0].value : null,
    orders: results[1].status === 'fulfilled' ? results[1].value : [],
    recommendations: results[2].status === 'fulfilled' ? results[2].value : [],
    errors: results
      .filter(r => r.status === 'rejected')
      .map(r => r.reason.message)
  };
}

BFF Implementation Checklist

Design Phase

  • Identify client types and their specific needs
  • Map backend services to aggregate
  • Define transformation requirements
  • Plan caching strategy
  • Design error handling approach

Implementation Phase

  • Set up BFF service skeleton
  • Implement service clients
  • Add aggregation logic
  • Create transformation layer
  • Implement caching
  • Add error handling with fallbacks
  • Set up monitoring/logging

Testing Phase

  • Unit test transformations
  • Integration test aggregations
  • Load test under realistic conditions
  • Test failure scenarios
  • Verify cache behavior

Technology Recommendations

PLAN Pro Stack BFF Options

Python/FastAPI:

@router.get("/dashboard/{user_id}")
async def get_dashboard(user_id: str):
    async with aiohttp.ClientSession() as session:
        tasks = [
            fetch_user(session, user_id),
            fetch_orders(session, user_id),
        ]
        user, orders = await asyncio.gather(*tasks)
    return DashboardResponse(user=user, orders=orders)

Rust/Axum:

use axum::{extract::Path, Json};
use tokio::try_join;

pub async fn dashboard(
    Path(user_id): Path<String>,
) -> Result<Json<DashboardResponse>, AppError> {
    let (user, orders) = try_join!(
        user_service::get(&user_id),
        order_service::list(&user_id),
    )?;

    Ok(Json(DashboardResponse { user, orders }))
}

Next.js API Routes:

// app/api/dashboard/[userId]/route.ts
import { NextResponse } from 'next/server';

export async function GET(
  request: Request,
  { params }: { params: { userId: string } }
) {
  const [user, orders] = await Promise.all([
    fetch(`${API_URL}/users/${params.userId}`).then(r => r.json()),
    fetch(`${API_URL}/orders?userId=${params.userId}`).then(r => r.json())
  ]);

  return NextResponse.json({ user, orders });
}

Best Practices

  1. Keep BFF Thin: Business logic belongs in services, not BFF
  2. Client Ownership: Each client team owns their BFF
  3. Version Carefully: BFF APIs should be versioned
  4. Monitor Latency: Track aggregation overhead
  5. Cache Aggressively: Use appropriate caching at each level
  6. Fail Gracefully: Never let one service failure break the whole response
  7. Document Contracts: Clear API documentation for frontend teams

Score

Total Score

70/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

+10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

Reviews

💬

Reviews coming soon