BFF (Backend for Frontend)

フロントエンドごとに専用のバックエンドを用意し、クライアントに最適化された API を提供するパターン

アーキテクチャAPI

BFF とは

BFF (Backend for Frontend) は、フロントエンドごとに専用のバックエンドを用意し、クライアントに最適化された API を提供するパターンである。Sam Newman が提唱。詳細は「BFF パターン」を参照。

なぜ必要か

マイクロサービス環境では、モバイルアプリと Web アプリで必要なデータの形式や量が異なる。汎用 API を 1 つだけ用意すると、モバイルには不要なフィールドまで返却され、通信量が増える。BFF を設けることで、各クライアントに最適化されたレスポンスを返せる。

❌ 汎用 API:
  モバイル: /api/users/123 → 50 フィールド返却 (大半は不要)
  Web: /api/users/12350 フィールド返却 (別のフィールドが不要)

✅ BFF:
  モバイル → Mobile BFF → { name, avatar } (必要最小限)
  WebWeb BFF → { name, email, orders } (Web に最適化)

アーキテクチャ

各フロントエンドに専用の BFF を配置し、背後のマイクロサービス群から必要なデータだけを集約して返す。BFF はクライアントごとのデータ整形に専念し、ビジネスロジックは持たない。

モバイルアプリ → Mobile BFF (Lambda) → マイクロサービス群
Web アプリ    → Web BFF (Lambda)    → マイクロサービス群
管理画面      → Admin BFF (Lambda)  → マイクロサービス群

BFF vs 汎用 API vs GraphQL

BFF と汎用 API vs GraphQL の違いを以下にまとめる。

観点 汎用 API BFF GraphQL
Over-fetching 発生する 解決 解決
クライアント最適化
バックエンド数 1 クライアント数分 1
複雑さ 低い 中〜高

Lambda での BFF

Lambda での BFF のコード例を示す。

// Mobile BFF: モバイルに最適化されたレスポンス
export const mobileHandler = async (event: APIGatewayProxyEventV2) => {
  const userId = event.pathParameters?.id;
  const [user, orders] = await Promise.all([
    userService.get(userId!),
    orderService.getRecent(userId!, 3), // モバイルは直近 3 件のみ
  ]);
  return {
    statusCode: 200,
    body: JSON.stringify({
      name: user.name,
      avatar: user.avatar,
      recentOrders: orders.map(o => ({ id: o.id, total: o.total })),
    }),
  };
};

BFF の注意点

BFF の注意点を以下にまとめる。

注意点 対策
BFF の肥大化 ビジネスロジックを BFF に入れない
重複コード 共通ロジックをライブラリに抽出
BFF の数が増える GraphQL で代替を検討

いつ BFF を使うか

いつ BFF を使うかの判断基準を以下にまとめる。

ケース 推奨
モバイル + Web で異なるデータが必要 ✅ BFF
単一のフロントエンド ❌ 汎用 API で十分
クライアントが柔軟にデータを選びたい GraphQL

より深く学ぶには関連書籍が役立つ。

この記事は役に立ちましたか?

関連用語

関連する記事