はじめに
英語の技術動画で System Design を学ぶシリーズ。
前回の REST API に続いて、今回は GraphQL との比較。
GraphQLとは
- Meta が開発した、API のためのクエリ言語
- API が扱うデータのスキーマを提供し、クライアントが必要なものだけを要求できる
- クライアントとバックエンドサービスの間に位置する
- 複数のリソース要求を1つのクエリに集約できる
クエリ(取得)以外に2種類の操作がある。
| 操作 | 役割 |
|---|---|
| query | データの取得 |
| mutation | データの変更 |
| subscription | データ変更の通知を受け取る |
前提:REST との共通点
まず違いより先に、共通点が押さえられていた。
- どちらも HTTP リクエストを送り、HTTP レスポンスを受け取る
- どちらも URL 経由でリクエストする
- どちらも同じ形の JSON を返せる
「GraphQL は REST を置き換える別のプロトコル」ではない、というのが出発点。
書店APIで比べる
REST の場合
リソース中心で、各リソースは URL で識別される。
GET /books/1
ここでポイントなのが、レスポンスに authors が含まれるかどうかは実装依存だということ。
実装によっては著者を別の REST 呼び出しに分けることもある。
つまりレスポンスの形を決めるのは API 実装者。
GraphQL の場合
3段階に分かれる。
1. 型を定義する
type Book {
id: ID!
title: String!
authors: [Author!]!
}
type Author {
id: ID!
name: String!
}
型は「どんなデータが存在するか」を表す。
2. Query を定義する
type Query {
book(id: ID!): Book
}
3. エンドポイントにリクエストする
query {
book(id: 1) {
title
authors { name }
}
}
違いは「誰がレスポンスの形を決めるか」
| REST | GraphQL | |
|---|---|---|
| リソースの指定 | URI(/books/1 など) |
スキーマ |
| 返すフィールド | API 実装者が決める | クライアントが指定する |
| エンドポイント | リソースごとに複数 | 単一 |
REST の例では「著者も関連リソースとして含める」と API 実装者が決めていた。
GraphQL では何を含めるかをクライアントが決める。
GraphQL の利点:関連データを1回で取れる
GraphQL は URL でリソースを指定せず、スキーマで表現する。
スキーマにはリソース間の 関連(relationship) が定義されているので、関連データまで含めた複雑なクエリを1回で投げられる。
REST で同じことをやろうとすると、クライアント側から複数回リクエストを投げることになる。
これがいわゆる N+1 問題。
GraphQL の欠点
動画の後半はほぼ全部こっち。ここが本題という印象。
1. 初期投資が大きい
REST の良さは「他人の API を叩くのに特別なライブラリが要らない」こと。cURL やブラウザだけで済む。
GraphQL はクライアント側・サーバ側の両方でそれなりのツール整備が必要で、初期投資が大きい。
単純な CRUD API では、そのコストに見合わないことがある。
2. キャッシュしづらい
- REST … 取得は HTTP GET。GET のキャッシュ挙動は明確に定義されていて、ブラウザ・CDN・プロキシ・Web サーバがそれを活用してくれる
- GraphQL … 単一エンドポイント、しかもデフォルトが POST。HTTP キャッシュをフルに活かせない
設定次第で改善はできるが、細かい話になるうえに追加作業であり、正しくやるのは簡単ではない。
3. クライアントが自由すぎる危険
「必要なデータだけ取れる」は、裏を返すとクライアントが自由に重いクエリを投げられるということ。
動画で挙げられていた例:モバイルアプリが新機能をリリース
→ そのクエリがバックエンドの重要テーブルに想定外のフルスキャンを発生させる
→ アプリが公開された瞬間に DB が落ちる
対策はあるが、その分また実装が複雑になる。このリスクを防ぐコストも込みで判断すべき、という話。
まとめ
結論は「唯一の正解はない」。ソフトウェアエンジニアリングはトレードオフ、というお決まりの締め方だった。
ざっくり言えば、
- フロントの要求が複雑・変わりやすい → GraphQL の旨味が出る
- シンプルな CRUD、キャッシュを効かせたい → REST で十分
REST 側の理解が前提になっている動画なので、#1 を見てからのほうが入りやすいと思う。
覚えておきたい英単語
| 英語 | 意味 | 動画での使われ方 |
|---|---|---|
| mutation | 変更(データ更新操作) | applying data modifications |
| subscription | 購読(変更通知の受信) | receive notifications on data modifications |
| single point of entry | 単一の入口 | GraphQL has a single point of entry |
| nuanced | 細かい機微がある | the detail is very nuanced |
| not trivial | 簡単ではない | getting it right is not trivial |
| tradeoff | トレードオフ | software engineering is about tradeoffs |