フロントエンド用バックエンド (BFF) パターンの理解: 簡単なガイド

フロントエンド用バックエンド (BFF) パターンの理解: 簡単なガイド

マイクロサービス アーキテクチャでは、当社のシステムは、ユーザー サービス、注文サービス、製品サービスなど、多数の小規模で焦点を絞ったサービスに分割されます。

しかし、この情報をユーザーに表示する場合、デバイスごとにニーズは大きく異なります。高速デスクトップ コンピューター上の Web ブラウザーには、テーブル、サイドバー、グラフが満載のリッチなダッシュボードが必要です。低速のセルラー ネットワーク上のモバイル アプリでは、帯域幅とバッテリーを節約するために、シンプルで軽量なレイアウトが必要です。スマートウォッチ アプリには 1 行のテキストのみが必要な場合があります。

これらすべてのフロントエンドがまったく同じバックエンド API をクエリする場合、誰かが妥協する必要があります。モバイル アプリは大量の役に立たないデータをダウンロードすることを強いられるか、Web アプリは必要なものをすべて取得するために何十もの個別のネットワーク リクエストを行うことを強いられます。

これは、フロントエンド用バックエンド (BFF) パターン によって解決されるまさに問題です。このガイドでは、このパターンを簡単な言葉で説明し、現実世界の類似点を見て、それを標準の API ゲートウェイと比較し、実際のコード実装について説明します。


現実世界のたとえ: レストランのメニュー

3 つのまったく異なるタイプの食事を提供するレストランを想像してください。

  1. 食品評論家。詳細な成分リストを含む完全な 5 コースのテイスティング メニューを望んでいます。
  2. 忙しい通勤者で、電車の中で簡単に包装済みの軽食を食べたいと考えています。
  3. 子供は、スパイシーな食材を使わず、少量でシンプルなお子様の食事を望んでいます。

もしレストランに、3 つのオプションすべてを詳細に記載した 1 つのメニューしかなかったとしたら、それは圧倒されるでしょう。通勤者は5品コースのレシピを読むのに時間を無駄にし、子供の親は簡単な食事の選択肢を見つけるのに苦労するでしょう。

代わりに、レストランでは 3 つのカスタム メニュー (テイスティング メニュー、エクスプレス To-Go メニュー、キッズ メニュー) を印刷します。

各メニューは同じキッチン (マイクロサービス) から取得されますが、その顧客 (クライアント) に合わせて選択肢の形式とサイズが設定されます。

このシナリオでは:

  • キッチンマイクロサービス (ユーザー、カタログ、支払い) を表します。
  • カスタム メニューはあなたの BFF (Web BFF、Mobile BFF、Watch BFF) です。
  • ダイナーフロントエンド (デスクトップ ブラウザ、モバイル アプリ、スマートウォッチ) です。

問題: 「万能」API

マイクロサービスが最初に普及したとき、多くのチームは、すべてのフロントエンド クライアントを処理する単一の共有 API ゲートウェイを構築しました。

Web フローとモバイル フローを比較したフロントエンド用バックエンド (BFF) アーキテクチャ図

単一のエントリ ポイントは優れていますが、共有 API にはいくつかのスケーリング ボトルネックが発生します。

  • モバイルのペイロードの膨張: デスクトップ Web アプリには、ユーザーの注文履歴、請求先住所、プロフィール写真、ロイヤルティ ポイントが必要です。モバイル アプリでは「最後の注文: 発送済み」と表示するだけで済みます。共有 API を使用すると、モバイル アプリはプロファイル ペイロード全体をダウンロードするため、貴重なデータが無駄になり、読み込み時間が遅くなります。
  • API ボトルネック: 単一のチームが共有ゲートウェイのボトルネックになります。 iOS チームが小さなレイアウト フィールドを変更したい場合、共有ゲートウェイ チームが新しいバージョンをデプロイするまで待たなければならず、開発サイクルが遅くなります。
  • さまざまなセキュリティ ニーズ: Web ブラウザーではクロスサイト スクリプティング (XSS) を防ぐために Cookie ベースのセッションが必要になる場合がありますが、モバイル アプリではトークンベースの OAuth ヘッダーが好まれます。両方を単一サーバーで処理すると、複雑で乱雑なコードが作成されます。

解決策: BFF パターン

BFF パターンでは、すべてのデバイスに 1 つの巨大なゲートウェイを作成するのではなく、フロントエンド アプリケーションごとに 1 つの専用バックエンド サーバーを構築することを推奨しています。

以下が得られます:

  • Web BFF: デスクトップ ブラウザからのリクエストを処理します。完全なプロフィール、製品カタログ、詳細なチェックアウト情報が集約されています。
  • モバイル BFF: iOS および Android アプリからのリクエストを処理します。データを集約し、不要なフィールドをフィルタリングして除去し、最終応答を圧縮して高速なパフォーマンスを保証します。

API ゲートウェイと BFF: 違いは何ですか?

これら 2 つのパターンはどちらもクライアントとマイクロサービスの間に位置するため、混同されることがよくあります。違いは次のとおりです。

特集 一般的な API ゲートウェイ フロントエンド用バックエンド (BFF)
ゲートウェイの数 通常、システム全体に 1 つ 複数 (クライアント デバイスのタイプごとに 1 つ)。
責任 高レベルのルーティング、レート制限、およびグローバル セキュリティ。 データを集約し、特定のフロントエンド向けにペイロードを調整します。
所有権 専任のバックエンド/プラットフォーム インフラストラクチャ チームによって管理されます。 対応するアプリを構築する フロントエンド チームによって管理されます。
カスタマイズ 低い。変更はすべてのクライアントに影響します。 高い。変更は 1 つのクライアント アプリケーションにのみ影響します。

実用的な実装 (Node.js/Express)

これが実際にどのように機能するかを理解するために、簡単な Node.js の例を書いてみましょう。

内部で 2 つのマイクロサービスが実行されていると想像してください。

  • ユーザー サービス (基本的なユーザー プロファイル情報を返します)
  • 注文サービス (完全な詳細を含む注文のリストを返します)

ウェブ BFFモバイル BFF を構築して、デスクトップ サイトとモバイル アプリに異なる方法でサービスを提供したいと考えています。

1. 共有マイクロサービス モック

まず、基盤となる 2 つのマイクロサービスのモック データは次のとおりです。

// Internal User Service Response
const userProfile = {
    id: 42,
    username: "dev_coder",
    email: "coder@ghaznix.com",
    avatarUrl: "https://ghaznix.com/avatars/42.png",
    preferences: { theme: "light", newsletter: true }
};

// Internal Order Service Response
const orderHistory = [
    { id: "ORD-99", date: "2026-06-25", items: ["Laptop", "Mouse"], status: "Shipped", tax: 15.00, total: 1215.00 },
    { id: "ORD-88", date: "2026-05-12", items: ["Keyboard"], status: "Delivered", tax: 5.00, total: 105.00 }
];

2. Web BFF (完全な詳細ペイロードを返す)

デスクトップ画面にはフィールドを表示するための十分なスペースがあるため、Web BFF はすべてのフィールドを集約します。

const express = require('express');
const webBff = express();

webBff.get('/dashboard', (req, res) => {
    // Web needs everything: profile + full order details + settings
    const responsePayload = {
        user: {
            username: userProfile.username,
            email: userProfile.email,
            avatar: userProfile.avatarUrl,
            theme: userProfile.preferences.theme
        },
        orders: orderHistory // Send all order details, taxes, and items
    };
    
    res.json(responsePayload);
});

webBff.listen(3001, () => console.log('Web BFF running on port 3001'));

3. モバイル BFF (最小化された集約されたペイロードを返す)

モバイル BFF は不要なフィールド (電子メール、設定、税金など) を除外し、注文アイテムを集約して帯域幅を節約します。

const express = require('express');
const mobileBff = express();

mobileBff.get('/dashboard', (req, res) => {
    // Mobile only wants: username, avatar, and summary of the latest order
    const latestOrder = orderHistory[0];
    
    const responsePayload = {
        user: {
            username: userProfile.username,
            avatar: userProfile.avatarUrl
        },
        latestOrderStatus: {
            orderId: latestOrder.id,
            status: latestOrder.status,
            date: latestOrder.date,
            itemCount: latestOrder.items.length // Send count instead of array list
        }
    };
    
    res.json(responsePayload);
});

mobileBff.listen(3002, () => console.log('Mobile BFF running on port 3002'));

ペイロードサイズの比較

  • Web BFF 応答サイズ: ネストされた構成、基本設定、完全な注文リスト、税金、品目などが含まれます (約 400 バイト)。
  • モバイル BFF 応答サイズ: 必要最小限のキーと値のペアが 6 つだけ含まれています。 (約 120 バイト - ネットワーク サイズが 70% 削減!)。

BFF パターンの長所と短所

BFF パターンは非常に効果的ですが、次のようなトレードオフがあります。

アドバンテージ (プロ) デメリット(短所)
最適化されたクライアント パフォーマンス: クライアントは必要な正確なデータのみをロードするため、バッテリー消費とメモリ使用量が削減されます。 コードの重複: 複数の BFF コードベースで同様のデータ取得ロジックを作成することになる可能性があります。
リリース サイクルの短縮: モバイル フロントエンド チームは、Web 開発者と調整することなく BFF サーバーを更新できます。 サーバー数の増加: 1 つの API ゲートウェイを管理する代わりに、複数の BFF サービスをデプロイして管理する必要があります。
簡略化されたフロントエンド コード: クライアントは、複雑な並べ替え、フィルタリング、マージ ロジックを処理する必要はありません。受け取った JSON を表示するだけです。 セキュリティ管理: SSL/TLS 証明書、レート制限ルール、およびファイアウォールは、複数のゲートウェイにわたって管理する必要があります。

## 結論

フロントエンド用バックエンド (BFF) パターンは、Web、モバイル、IoT デバイスなど、複数の種類のクライアントにサービスを提供するシステムのための強力なアーキテクチャです。特定のフロントエンドごとにカスタマイズされたゲートウェイを作成することで、クライアント開発を分離し、ペイロード サイズを最小限に抑え、より高速で応答性の高いユーザー エクスペリエンスを提供します。

システムに Web アプリケーションが 1 つしかない場合は、共有 API ゲートウェイで十分です。ただし、Web アプリケーションと並行してモバイル アプリや特殊なデバイス エクスペリエンスを構築し始めると、フロントエンドとバックエンドのアーキテクチャをクリーン、最適化、独立した状態に保つための最良の方法は、BFF の実装です。


Ghaznix ブログでソフトウェア開発とバックエンド エンジニアリングの洞察をさらに詳しく見る→