Backend for Frontend(BFF)とは、特定のフロントエンドのために構築された専用のバックエンドサービスです。すべてのクライアント(ウェブ、iOS、Android、サードパーティ)が同じ汎用バックエンドと通信する代わりに、それぞれが独自のサーバーサイドレイヤーを持ち、マイクロサービスからのデータを集約し、そのインターフェースが必要とする正確なペイロードに整形します。
Sam Newmanは、SoundCloudでの作業に基づいて、2015年にこのパターンを命名し普及させました。それから10年以上経った今でも、BFFパターンは、複数のクライアントアプリケーションの背後でマイクロサービスを実行しているチームにとって標準的なツールであり、Microsoftはこれを主要なクラウドアーキテクチャパターンとして文書化しています。
BFFが解決する問題
単一のウェブアプリケーションと単一のバックエンドから始まったシステムを想像してみてください。バックエンドはRESTエンドポイントを公開し、ウェブアプリケーションはそれらを利用し、すべてがシンプルでした。その後、会社はモバイルアプリを出荷しました。次にパートナー連携、そしてスマートウォッチウィジェット。突然、4つのまったく異なるクライアントがすべて同じバックエンドからデータを取得するようになり、そのバックエンドは一度に全員を満足させようとします。
これにより、2つの繰り返し発生する問題が生じます。
過剰なフェッチと不足なフェッチ。 汎用エンドポイントは固定された形式のデータを返します。デスクトップダッシュボードは、注文履歴、レコメンデーション、アカウント設定を含む完全な顧客記録を1つのレスポンスで欲しがるかもしれません。不安定なセルラー接続のモバイルアプリは、3つのフィールドだけを欲しがり、それ以上は必要ありません。両方が同じエンドポイントにアクセスすると、どちらか一方が誤った量のデータを取得します。モバイルクライアントは、破棄しなければならない肥大化したペイロードをダウンロードするか(過剰なフェッチ)、または必要なものを組み立てるために複数回の追加ラウンドトリップを実行しなければなりません(不足なフェッチ)。
おしゃべりなクライアント。 バックエンドが画面に合わせて調整されていない場合、クライアントは多数の呼び出しを行うことでそれを補います。プロファイルデータ、通知数、フィードを必要とするモバイルのホーム画面は、3つまたは4つの個別のリクエストを3つまたは4つのマイクロサービスに発行し、その後、デバイス上で結果を結合するかもしれません。追加のラウンドトリップごとに遅延とバッテリー消費が発生し、オーケストレーションロジックはクライアントに漏れ出し、テストやバージョン管理が困難になります。
根本的な緊張は技術的なものと同じくらい組織的なものです。共有バックエンドは、すべてのフロントエンドチームから競合する要求を受けます。あるチームの変更は、出荷される前に他のすべてのチームのニーズに対して検証される必要があり、これによりバックエンドはボトルネックとなり、チーム間の摩擦の原因となります。
BFFパターンの仕組み
BFFパターンは、1つのフロントエンドとダウンストリームサービスの間にある薄いサーバーサイドレイヤーを導入します。各インターフェースは独自のバックエンドを取得します。
[ Web app ] ---> [ Web BFF ] ---\
[ iOS app ] ---> [ iOS BFF ] -----> [ Microservices ]
[ Android app] ---> [ Android BFF ] ---/
各BFFは、クライアントのために3つの役割を果たします。
- 集約。 画面が必要とするダウンストリームマイクロサービスを呼び出し、それらのレスポンスを結合することで、クライアントは5回ではなく1回のリクエストで済むようになります。これは、単一のユーザーエクスペリエンスに適用されたAPI集約です。このアイデアの一般的なバージョンを知りたい場合は、APIアグリゲーターパターンに関する解説をご覧ください。
- 整形。 フィールドをトリミングし、クライアントにわかりやすい用語に名前を変更し、ネストされた構造を平坦化し、インターフェースが期待する形式で値をフォーマットします。モバイルBFFは軽量なペイロードを返し、デスクトップBFFは豊富なペイロードを返します。
- 変換。 ページネーション戦略、そのクライアントに合わせたレスポンスキャッシュ、プロトコル選択など、クライアント固有の懸念事項を処理し、それらの決定を下の共有サービスに強制しません。
ダウンストリームマイクロサービスは汎用でフロントエンドに依存しないままです。それらはクリーンで再利用可能な機能を提供します。BFFはクライアント固有の整形が施される場所であり、そのロジックをマイクロサービスとクライアントアプリの両方から分離します。基礎となるサービスレイヤーに慣れていない場合は、マイクロサービスとAPIの概要、およびモノリスからマイクロサービスへの移行が文脈を提供します。
クライアントエクスペリエンスごとに1つのBFF
ニューマンの核となるガイダンスは短く、「1つのエクスペリエンスに1つのBFF」です。iOSとAndroidアプリが著しく異なるエクスペリエンスを提供する場合は、それぞれに独自のBFFを与えます。ウェブアプリとモバイルアプリが分岐する場合も同じルールが適用されます。
このルールの目的は、各BFFの焦点を絞ることです。単一のBFFが異なるニーズを持つ2つのクライアントを同時に処理しようとすると、条件付きロジック(「モバイルならこれを返す。ウェブならあれを返す」)が蓄積され始め、結局は同じ調整問題を抱える汎用バックエンドに戻ってしまいます。焦点の絞られたBFFは小さく保たれ、それがこのパターン全体のメリットを生み出す特性です。
ニューマン自身がSoundCloudの例から引き出した、納得のいく例外があります。1つのチームが、ほぼ同じエクスペリエンスを共有するiOSアプリやAndroidアプリのような2つの類似したクライアントを所有している場合、それらの間で単一のモバイルBFFを共有することは妥当です。決定要因は所有権と類似性であり、プラットフォーム名ではありません。このルールはデフォルトであり、法律ではありません。
所有権はフロントエンドチームに属する
BFFはプラットフォームチームが構築して引き渡すレイヤーではありません。クライアントを所有するフロントエンドチームがそのBFFを所有します。これが、このパターンを機能させる後半の要素です。
フロントエンドチームがBFFを所有すると、リリースサイクルを制御し、言語とランタイムを選択し、バックログの優先順位を付け、クライアントとそのバックアップサービスへの変更を同時に出荷することができます。新しい集約エンドポイントを必要とするUI変更のために、別のバックエンドチームにチケットを提出し、そのチームのキューが空くのを待つ必要はありません。問題を抱えるチームが修正を担当するのです。
この自律性が真の勝利です。BFFは境界を移動させ、クライアント固有の決定がクライアントに責任を持つ人々によって行われるようにします。これは、API主導型コネクティビティの考え方が「エクスペリエンス」層を置く場所とまったく同じです。
BFF vs APIゲートウェイ
これは、BFFとAPIゲートウェイが図上では似ているため、多くのチームが戸惑う比較です。どちらもクライアントとサービスの間に入り込みます。どちらもルーティングと集約が可能です。しかし、それらが答える問いは異なります。
APIゲートウェイは、認証、レート制限、ルーティング、TLS終端、リクエストロギングなど、すべてのトラフィックの横断的懸念事項を処理する汎用エントリポイントです。プラットフォームチームまたはインフラストラクチャチームが所有し、意図的にクライアントから独立しています。1つのゲートウェイがすべての人に同じ方法でサービスを提供します。
BFFはその逆です。設計上クライアント固有であり、フロントエンドチームが所有し、その目的は各インターフェースごとに異なることです。これは1つのクライアントのペイロード整形が行われる場所であり、共有されたボトルネックではありません。
この2つは競合するものではありません。一般的な本番環境の構成では、APIゲートウェイが前面に位置し、認証、レート制限、すべてのトラフィックの監視を処理し、その後、各クライアントをゲートウェイの背後にある専用のBFFにルーティングします。Microsoftのリファレンスアーキテクチャはまさにこれを示しています。ゲートウェイが横断的懸念事項を管理し、その背後にクライアントごとに1つのサーバーレスBFFがあります。クライアント間で共通するものはゲートウェイを使用し、異なるものはBFFを使用します。(この対比の詳細バージョンは別の記事で扱いますが、ここではそれらが異なる層に位置し、異なるニーズに応えることを知っていれば十分です。)
周辺のゲートウェイの状況については、これらの比較記事が役立ちます。API管理 vs APIゲートウェイ、APIゲートウェイ vs ロードバランサー、サービスメッシュ vs APIゲートウェイ。
BFFを使用するタイミング
このパターンは、以下の条件が満たされる場合にその価値を発揮します。
- 複数の、本当に異なるクライアントが存在する。 ウェブ、モバイル、そしてパートナー連携など、それぞれが異なるデータニーズを持つ場合。エクスペリエンスが多様であればあるほど、BFFはより役立ちます。
- 共有バックエンドがボトルネックになっている。 すべてのフロントエンド変更がチーム間の交渉を強制する場合、クライアント固有の整形をチームごとのBFFに分割することで、調整コストが削減されます。
- クライアントに最適化されたペイロードが必要。 モバイルは軽量なレスポンスと積極的なキャッシュを必要とし、デスクトップは豊富な集約データを必要とします。BFFを使用すると、妥協することなくそれぞれを最適化できます。
- 特定のフロントエンドにより適した言語がある。 チームは、他のBFFが使用する言語とは独立して、そのクライアントに適したランタイムでBFFを構築できます。
BFFを使用しないタイミング
このパターンは無料ではなく、メリットなしにコストが増える明確なケースがあります。
- クライアントが1つしかない。 単一のインターフェースでは、BFFは単なる余分なホップに過ぎません。通常のバックエンドを構築してください。
- クライアントが同じリクエストを行う。 ウェブとモバイルがほぼ同じ形式のデータを欲しがる場合、別々のBFFは無駄な重複作業になります。代わりに統合してください。
- GraphQLがすでに整形の問題を解決している。 GraphQLでは、各クライアントが単一のエンドポイントから必要なフィールドを正確にクエリできるため、ペイロード整形に関してBFFが行うことの多くをカバーします。フロントエンド固有のリゾルバーを持つGraphQLレイヤーがある場合、別のBFF層は多くの場合、価値を追加しません。GraphQLとは何かを確認し、BFF層を追加する前にそれが適しているかを判断してください。
- ゲートウェイとマイクロサービスで十分である。 よりシンプルなシステムでは、適切に設計されたマイクロサービスの前にAPIゲートウェイを置くことで、専用のクライアントごとの層なしで許容可能な結果を提供できます。
BFFの正直なデメリット
BFFが適切な選択である場合でも、実際にコストが発生します。オープンな目で検討することが、このパターンをうまく活用するための一部です。
コードの重複。 これは見出しとなるトレードオフであり、Microsoftのドキュメントでも直接指摘されています。3つのBFFがすべて同じ認証チェックを呼び出したり、同じ日付を同じ方法でフォーマットしたりする必要がある場合、そのロジックは3回記述される傾向があります。あなたはカスタマイズのために重複を受け入れているのです。解決策は規律です。真に共有されるロジックはBFFがインポートするライブラリに保持し、BFF自体はクライアント固有の整形のために予約します。真の横断的懸念事項(認証、レート制限、監視)は、BFFごとに再実装するのではなく、ゲートウェイに押し上げます。
運用するサービスが増える。 各BFFは、独自のライフサイクル、パイプライン、オンコール体制、セキュリティ領域を持つ、別のデプロイ可能なユニットです。サービスが増えることは、運用上のオーバーヘッドが増えることを意味します。
追加のネットワークホップ。 クライアントはサービスと直接通信しなくなります。BFFはホップを追加するため、遅延が発生する可能性があります。通常、BFFがクライアントの複数回のラウンドトリップを排除するため、これは価値のあるトレードオフですが、測定すべきコストであり、安易に仮定すべきではありません。
BFFが肥大化するリスク。 BFFが複数のクライアントにサービスを提供し始めたり、マイクロサービスに属するビジネスロジックを取り込んだりすると、脱却しようとしていた汎用バックエンドに戻ってしまいます。BFFは薄く保つべきです。
ApidogでBFFコントラクトを同期させる
BFFを実際に運用する上で難しいのは「コントラクト」です。各BFFは独自のクライアント向けAPIを公開し、またその下にあるマイクロサービスのコントラクトにも依存します。これは、異なるレイヤーを所有するチーム間で多くのインターフェースが動的に変化することを意味し、それらの間のずれがバグやクライアントの破損につながります。

ここでApidogがワークフローに適合します。ApidogはAPI設計、テスト、モック、ドキュメント作成プラットフォームであり、各BFFのAPIコントラクトが、フロントエンドとバックエンドの両チームが連携できる単一の場所となります。
- コントラクトを最初に設計する。 Apidogのビジュアルデザイナーで、各BFFエンドポイントとそのリクエストおよびレスポンススキーマを、OpenAPIをベースに定義することで、コードが書かれる前にクライアント向けのデザインが合意されます。これはBFFレイヤーに適用されたコントラクトファーストアプローチであり、APIコントラクトを明確に保ちます。
- 存在しないうちにモックを作成する。 フロントエンドチームは、コントラクトが合意された日から、BFFやそのダウンストリームサービスが準備されるのを待つことなく、Apidogのスマートモックに対して開発を開始できます。
- コントラクトをテストする。 Apidogの自動テストとアサーションは、各BFFがクライアントが期待する集約され、整形されたペイロードを返すことを検証し、CIに組み込むことで、BFFレスポンスを壊すダウンストリームの変更を早期に検出します。
- 両側のためにドキュメント化する。 Apidogはコントラクトからインタラクティブなドキュメントを自動生成するため、BFFのAPIを参照するフロントエンドチームと、その下のサービスを所有するバックエンドチームが、単一の信頼できる情報源を共有できます。
範囲を明確にするために述べると、ApidogはBFFを構築、ホスト、実行するものではなく、APIゲートウェイでもありません。Apidogは、各BFFがその背後に持つAPIコントラクトを設計、モック、テスト、ドキュメント化する場所であり、BFFが進化するにつれてフロントエンドとバックエンドのチームを同期させるものです。各BFFを安定した適切に文書化されたコントラクトを持つ製品として扱うことが、このパターンを持続可能にする鍵です。
よくある質問
BFFはマイクロサービスですか? BFFはサーバーサイドサービスであり、マイクロサービス設定では通常その一つとして動作します。しかし、その役割は一般的なマイクロサービスとは異なります。マイクロサービスはビジネス機能を所有し、クライアントから独立しています。BFFは1つのクライアントのエクスペリエンスを所有し、そのクライアントのためにマイクロサービスを集約・整形するために存在します。これはエクスペリエンス層のサービスであり、ビジネス機能のサービスではありません。
いくつのBFFを持つべきですか? デフォルトは、明確に異なるクライアントエクスペリエンスごとに1つです。ウェブ用、iOS用、Android用などです。単一のチームがほぼ同じニーズを持つクライアントを所有する場合にのみ、2つを組み合わせます。1つのBFFがクライアントごとの条件付きロジックを蓄積し始めたら、さらに分割します。
GraphQLはBFFパターンを置き換えますか? ペイロード整形に関しては、置き換えることができます。GraphQLは、各クライアントが1つのエンドポイントから必要なフィールドを正確にリクエストできるため、クライアントごとのバックエンドなしで過剰なフェッチと不足なフェッチをカバーします。フロントエンド固有のリゾルバーを持つGraphQLレイヤーがある場合、別のBFF層はほとんど価値を追加しないことがよくあります。共有のGraphQLサーバーでは容易に提供できない、クライアントごとのオーケストレーション、プロトコル変換、またはランタイムの選択が必要な場合、BFFは依然として役立ちます。
BFFとAPIゲートウェイを一緒に使用できますか? はい、それは一般的です。APIゲートウェイは、認証、レート制限、監視など、すべてのクライアントで共有される懸念事項を処理し、適切なBFFにトラフィックをルーティングします。各BFFは、そのクライアントに固有のものを処理します。これらは異なる層に位置し、異なる役割を果たします。
BFFは誰が所有すべきですか? クライアントを所有するフロントエンドチームです。この所有権がパターンの中核をなします。これにより、チームはUI変更とバックエンドエンドポイントを一緒にリリースし、独自のランタイムを選択し、別のバックエンドチームのキューを待つことなく作業を進めることができます。
BFFはレイテンシを追加しますか? 1つのネットワークホップを追加するため、コストがかかります。実際には、いくつかのクライアントからサービスへのラウンドトリップを1つのクライアントからBFFへのリクエストに置き換え、BFFがサービスの近くで並行してサービスを呼び出すことができるため、通常はクライアント全体のレイテンシを削減します。どちらかの方法を仮定するのではなく、ワークロードに合わせて測定してください。
