フロントエンドから見たGraphQLとBFF
この記事は Medley(メドレー) Advent Calendar 2024 の 19 日目の記事です。
はじめに
こんにちは、メドレーの高橋です。
私は約3ヶ月ほど前に株式会社メドレーに入社しました。
以前はフロントエンドのリアーキテクトに際して既存システムにBFFを導入するようなプロジェクトに複数関わったりしていたのですが、メドレーに来て初めてGraphQLを用いた開発に携わりました。
BFFもGraphQLもクライアントサイドが主体になってデータ取得を最適化するという点で似た特徴があります。
この記事ではフロントエンドの接続先としての目線でBFFとGraphQLについて個人的な所感を比較を交えて書いていきます。
この記事で書くこと
フロントエンドからのAPI呼び出し先として見た時の
- GraphQLとBFFの違いがフロントエンドに与える影響
- それぞれ触った感想
この記事で書かないこと
- BFFの設計や実装の詳細
- GraphQLサーバの設計や実装の詳細
- フロントエンド以外の視点からのBFFやGraphQL
GraphQLとBFF
詳細は長くなるため出来るだけ割愛したいのですが、まずは簡単にそれぞれがどの様なものなのか説明しておきます。
GraphQLとは
GraphQLは「APIのクエリ言語」とよく説明されます。
データの型とそれらの操作や取得に必要な関数をschemaとして定義し、フロントエンドはschemaを基に必要なフィールドを指定します。
より具体的な説明は公式ドキュメントを参照して欲しいのですが、この記事の前提としては以下のポイントを押さえていれば良いと思います。
- GraphQL自体は仕様(あるいは規格)であり、基本的にはGraphQLを実現するフレームワークなどを用いて実装する
- フロントエンドは定義されたデータ型から必要なフィールドを指定して必要な分だけ取得する
BFFとは
Backend For Frontend の略で、文字通りフロントエンドのためのバックエンドとして置かれるサーバ(及びその様な設計パターン)のことです。
主に複数のAPIサーバに対してリクエストを行うことによるフロントエンドの複雑さを吸収するレイヤーとして導入されます。
その他にもプロジェクトによって様々な役割を担うことがあります。
導入事例を紹介している記事も多数ありますが、Netflixの事例なんかは分かりやすいと思います。
BFFでGraphQLを使う。というパターンも結構ありますね。
ポイントとしては以下です。
- システム全体として抱える課題を解決するための設計パターン
- フロントエンドのためのAPIサーバである
- 主に複数のAPIサーバへのリクエストを取りまとめたり、複数のプラットフォームへの窓口としての役割を担い、フロントエンドからはBFFのみに対してリクエストすることが多い。
以降この2つをフロントエンドからのリクエスト先という目線で感じたことを書いていきます。
技術的な制限
フロントエンドで使用できるライブラリなど、技術選定寄りの話です。
GraphQL
先ほどの紹介でGraphQLでの開発ではそれを実現するフレームワークやライブラリを使用するという話をしました。
これはGraphQLサーバだけではなくクライアントサイドにも言える事です。
リクエスト先のAPIがGraphQLの場合フロントエンドはそれに対応したApollo ClientやRelayなどのライブラリを使用することになり、fetch
APIを直接使用したりaxiosの様なライブラリの利用は難しくなります。
通常あまり問題にはなりませんが、良くも悪くも「選択肢が減る」という事実は技術選定時などには押さえておきたいポイントです。
例えば、Next.jsのApp Routerではfetch
に独自のパッチを当ててキャッシュの制御を行なっています(v15でまた仕様が変わりましたが)。
これを最大限利用したい場合、リクエスト先がGraphQLだと少し困りそうです。
BFF
リクエスト先がBFFの場合、当然GraphQLの様な制限はありません。
その分プロジェクトごとに意思決定することは多くなりますが、BFF特有の課題というわけでもありません。
感想
APIがGraphQLだと技術選定において考えることは減りますが、個人的にはトレンドの移り変わりが比較的早いフロントエンドにおいては選択肢が多い方が嬉しい気がしています。
インターフェース
APIのレスポンスやリクエストなどのインターフェースをどの様に定義しフロントエンドと共有するか、という視点についてです。
GraphQL
GraphQLの仕様に則りschemaを記述します。
自由度は意外と高いですが、あくまでGraphQLの世界の中での良いプラクティスを考えるだけです。
大抵の場合はコードからGraphQL schemaを自動生成するツールを使用するのではないでしょうか。
BFF
BFFのインターフェースをどの様に決定するかは、プロジェクトごとの事情によってかなり変わってきます。意思決定しなければならない事が多数あります。
よくあるケースではおそらくフロントエンドを設計・実装するにあたってフロントエンドの目線でインターフェースを定義し、それに則りAPIを実装する様なフローになると思います。
何を使ってインターフェースを記述するかも考える必要があります。
型やapi clientの自動生成はやっておきたいところなので、OpenAPI generatorの様なものを使うのかtRPCを採用するのかなど技術選定段階からフロントエンドとの共有方法を考えることになります。リポジトリ戦略とかも絡んできますね。
さらにはBFFでどこまでデータ構造をフロントエンド用に加工するのか、というような責任分解点の定義も必要でプロジェクトの固有ルールとして運用していくことになります。
感想
個人的にはGraphQL schemaを基にフロントエンドで都度必要なfieldをqueryするという体験は非常に好きです。
BFFはどこまでフロントエンドの都合にあわせるかという点が難しいものの、プロジェクトの都合に合わせて柔軟に設計を変えられる点は良いと思います。
一方で前述の通り決める事が多く、有識者がいないとなかなか進まない場合もあるので導入にあたっての初期フェーズがすごく大変なイメージがあります。
設計次第ですが、フロントエンドに寄りすぎるとエンドポイントや内部のロジックなども使い回しづらくなり開発工数も大きくなりやすいですね。
BFFでGraphQLを採用すればBFFの辛いポイントはある程度解決しそうですが、責任分解点の定義などのBFF固有の課題は全て消えるわけではなさそうです。
コードを書いて感じる違い
データ構造の捉え方
GraphQLサーバからのレスポンスは基本的にフロントエンドからはschemaだけを見ていればよく、認知負荷が低く感じました。
一方でBFFは後ろにある各バックエンドのどのエンドポイントがどんなレスポンスを返すかを整理しながらBFFのレスポンスを設計することになるので、フロントエンド目線でもそれらをある程度意識して設計することになります。(再三言いますがBFFの設計や運用方法次第ではあります)
加えてBFFはエンドポイントの数が多くなりがちで、「Aのデータを返している既存のエンドポイントはこれとこれとこれで、今回は追加でBのデータも必要だけどデータCはいらないから新しくエンドポイントが必要でその場合どのバックエンドのどのエンドポイントの、、、」みたいに色々な情報を集めないといけない印象があります。
これは「BFFを採用する必要がある=ある程度複雑なシステムである」という背景と、BFFを導入したことによるフロントエンド開発の作業範囲の拡大が問題だと思います。
この問題はおそらくBFFをGraphQLで作ったとしても解決しないでしょう。
データフェッチコロケーション
データの取得に関する記述はそのデータを必要とするコンポーネントの近くで定義しようという考え方です。
GraphQLにはFragment Colocationという考え方があります。
各コンポーネントが必要なデータをfragmentとして自身で宣言し、実際にqueryを行う親コンポーネント等はそのfragmentを参照するという形をとります。
詳細は省きますが、GraphQLではこのようにデータ取得のコロケーションを後押しする方法があるということです。
一方BFFの場合はただの設計パターンの話なので「BFFだから云々...」ということは特にないのですが、現状GraphQLを使わない場合React Server Components(実質的にはNext.jsのApp Router)以外でうまくコロケーションするのはなかなか難しいでしょう。
逆にApp Routerを使う場合はGraphQL以外の方が嬉しいという。。難しい。
GraphQLのFragment Colocationは個人的にすごく好きですが、コンポーネント内の実装にも結構GraphQLに関連するコードが入ってきやすく常にGraphQLを意識させられる感覚があります。
あとIDEの対応がちょっと微妙な気がします。。(VSCodeユーザー)
学習コスト
GraphQL自体はそれほど難しいものでは無いと思います。
しかし実際に開発するにあたっては、使っているGraphQL Clientなどについても知識が必要になるためそこそこの学習コストがかかってくる印象です。
特に私が関わっているプロダクトではApolloを使用しているのですが、Apollo特有のキャッシュ管理やreact-apolloが提供するhooksの挙動など新しく覚えることは結構多かったと思います。
BFFについては、どちらかというとプロジェクト固有のルールや設計などが多くなりやすいためオンボーディングにかかるコストが高くなりやすいイメージがありますがプロジェクトに依るという感じでしょう。
最後に
最初から述べている通りそもそも比べるようなものではないのですが、GraphQL・BFFの特有の事情がフロントエンドの開発においても結構影響があり、違いが出て面白いと思い今回の記事を書いてみました。
特に結論もなく全体的に私の感想ばかりですが、両方を触った人の感覚ということで何かの参考になれば幸いです。
Medley(メドレー) Advent Calendar 2024 20 日目の明日は @ogaclejapanさんの『Jetpack Composeで始めるServer Cache State』です!
Discussion