Production Ready GraphQL を読んで
を読んで、学んだこと、感想をメモしていく。
One-Size-Fits-All API とは、あらゆるユースケースに対応した API のこと。
SoundCloud の話
モバイル API では、例えば Web API よりもペイロードのフットプリントやリクエスト頻度を小さくするのが賢明。既存のモノリス API はこれを考慮しておらず、モバイルのニーズを知らずに別のチームによって開発されていた。そのため、アプリが新しいエンドポイントを必要するたびに、まずフロントエンド・チームがバックエンド・チームにこれが本当にそうであることを納得させる必要があり、それからストーリーを書き、優先順位をつけ、選び、開発し、フロントエンド・チームに伝える必要があった。
メイン API に高度なカスタマイズ・オプションを追加する代わりに、ユースケースごとに独自の API サーバーを用意することにした。これによって開発者は、エンドポイントベースの API が得意とする他のユースケースを気にすることなく、それぞれのユースケースを効果的に最適化することができる。
このパータンを「フロントエンドのためのバックエンド」(BFF) と呼ぶ。
開発者は1つのユースケースのために管理しやすい API を書くことができ、汎用的な「One-Size-Fits-All」API を書くという罠に陥るのを避けることができる。
SDL (スキーマ定義言語) のすばらしいところは、言語にとらわれないこと。
どの言語で GraphQL API を実行していても、SDL は最終的なスキーマを記述する。
... on 型
は、GraphQL では インラインフラグメント と呼ばれる。
query {
cart {
discountedItems {
... on Product {
name
}
... on GiftGard {
code
}
}
}
}
Directive はクエリやスキーマの特定の部分にカスタム動作を追加するためのもの。
優れた API とは?
API は使いやすく、悪用されにくいものでなければならない。
(APIs should be easy to use and hard to misure)
優れた API は、正しいことをするのは簡単で、間違ったことをするのは本当に難しいものでなければならない。
GraphQL は本質的に、優れた API を設計することを容易にはしない。強力な型システムが付属しているが、それを正しく使わなければ、他の API スタイルと同じ罠に陥る可能性がある。
デザインファースト
デザインファーストのアプローチを取ることは、ほとんどの場合、より良い API を生み出すことになる。これを怠ると、一般的に、システム内部でどのように実装されているか非常に密接に結びついたデザインになってしまう。
最良のシナリオは、GraphQL のエキスパートとドメインのエキスパートが一緒に仕事すること。
API、特にパブリックな API は、一度公開されると変更が非常に難しい。最初に設計を考え、コンセプトをよく理解しておくことで、後々変更を加えるリスクを下げることができる。
クライアントファースト
GraphQL はクライアント中心の API.
何よりも まず クライアントのユースケースを念頭に置いて GraphQL API を設計することが非常に重要。
これを怠ると、往々にして汎用的な API になり、クライアントは自分の望むことを実現するために推測したり、大量のドキュメント読んだりする必要が出る。
プロセスのできるだけ早い段階で "最初のクライアント" と仕事をすること。
API の受け手となる人々と一緒に仕事をするよう努めるべきである。
You Aren't Going to Need it (YAGNI) は、API を設計する際に特に役立つ。つまり、それ以上のものを公開してはならない。
クライアントを念頭に置いた設計が役立つもう一つのことは、実装の詳細に 影響されるスキーマを設計しないようにすること。GraphQL スキーマは 機能への 入り口であり、バックエンドの実装の詳細と結びつけることは避けるべき。これはより良い API を作るだけでなく、内部的に関心事に結合された外部 API につきものの多くの問題を避けることにもなる。
GraphQL API を自動的に生成するソフトウェアやサービスを提供するベンダーはデータベースのスキーマを読み取り、それに基づいて GraphQL スキーマを自動生成する機能を持っている。このアプローチには以下の問題がある。
- スキーマがデータベースの構造に依存してしまい、柔軟性が失われる
- 生成された API は一般的であり、特定のクライアント (アプリなど) のニーズには合わない可能性がある
- クライアントが実際に必要としていない多くの情報や機能が API に含まれてしまうことがある (YAGNI)
既存の API 定義 (たとえば Swagger や OpenAPI) を使った GraphQL のスキーマを自動生成するツールも注意を払って使用すること。
- 設計の違い: REST と GraphQL は基本的に違う設計思想に基づいている。REST は「リソース」(データの塊) に焦点を当てますが、GraphQL はより手続き的な操作に焦点を当てる。
- 名前の問題: 自動生成ツールは、REST の命名規則 (例:
postUser
、putProduct
) をそのまま GraphQL に持ってくることがある。しかし、GraphQL では、もっと直感的な名前 (例:createUser
、updateUser
) が一般的。
ネーミング
The names are the API talking back to you, so listen to them
良いネーミングは、ドキュメントを読んだり、最悪推測したりする前に、その API が何をするものなのかという情報を即座に伝えてくれる。良いネーミングはそれだけで正しい設計に導いてくれることが多い。
ネーミングに関しては、一貫性が超重要。一貫していれば、新しい API を発見することは簡単に感じられる。
接頭辞の不一致が積み重なると、API を探索したり使ったりするのが難しくなる。
GraphQL のスキーマ設計においては「Principle of Least Astonishment(驚き最小の原則)」に従うことは、一般的に非常に良い考え。
GraphQL のスキーマ設計では「Make Impossible States Impossible」の原則を適用することが重要。この原則は、プログラムが不正な状態になることを防ぐために、型や構造を工夫してそもそもそのような状態を表現できないようにすることを目指す。
スキーマを使いやすく理解しやすくするための方法 まとめ
- field は単一の機能に特化させ、曖昧な field や汎用的な field を避ける
- スキーマが制約を設けられる場合は、実行時のロジックを避ける
- field や引数間の関係を表現するために、複雑なオブジェクトや入力タイプを使用し、「不可能な状態」を避ける
- オプションの入力や引数に対してデフォルト値を設定し、デフォルトの動作を明示的にする
GraphQL のコアな哲学は、クライアントが必要とするデータだけを消費できるようにすることです。そのため、スキーマを構築する際には、クライアントの具体的なニーズに応じたシンプルなフィールドを選択することが一般的に良いアイデアです。あまりに汎用的なフィールドは、特定の誰にも最適化されておらず、理解しにくいことが多いです。フィールドは、しばしば単一の機能に特化させ、その機能を非常にうまく実行するべきです。