GraphQLを久しぶりに使うことになったので、復習のために"Production Ready GraphQL"を読んだ。
book.productionreadygraphql.com
著者はGitHubとShopifyでGraphQL APIの開発に携わっていた人なので、信頼感がある。GraphQL APIの開発をしようとした人はだいたいGitHubとかShopifyとかのAPIリファレンスを参考のために読んだことがあると思う。
まず、この本では、GraphQLはクライアントの種類やユースケースの増加に伴う"One-Size-Fits-All"な設計のAPIの問題を解決するものであるとしている。ここで、"One-Size-Fits-All"は、各エンドポイントの機能を充実させて汎用的にしすぎることで、APIを使うのもメンテナンスするのも難しくなった状態のことをいう1。
"One-Size-Fits-All"を避けるために、各クライアントのユースケースに着目する。GraphQLを使って、適切な粒度のユースケースに基づいたデータのクエリやミューテーションを実行できるインタフェースをスキーマとしてクライアントに提供することで、クライアントはそのスキーマを利用して必要十分なデータだけを明快にやり取りできる。また、スキーマがあることで、クライアントは型やAPIドキュメントを利用して生産性高く開発できる。
一方、そのようなスキーマを継続的に提供するためには設計から運用までさまざまな考慮事項がある。それを解説するのがこの本である。このように、本の内容としては使いやすいスキーマにするための設計で考慮すべきことの説明を中心に据えつつ、サーバサイドの実装でのプラクティス、開発用ツール、開発フロー、運用や監視、公開API、分散アーキテクチャなど、現場で実際にGraphQLを利用した開発をするうえで必要になる話題を幅広く取り扱っている。
おもしろかった点
スキーマの設計とサーバサイドの実装はさしあたって詳しくなっておきたかったので何度か読み直した。おもしろかった点を挙げておく。
スキーマ設計
GraphQL APIの基礎となるスキーマの設計について"GraphQL Schema Design"で説明されている。おもしろかったのは次の点。
- スキーマでドメインモデルを適切に表現すること。ドメインモデル貧血症(anemic domain model)と同様にanemic GraphQLになりうる
- データストアに存在するデータだけではなく、導出できる値も必要ならフィールドとして返すべき
- nullabilityについて
- not nullからnullableに変更する場合は破壊的変更になる。分散アーキテクチャの採用によって、一時的なエラーによりnullを返したくなるケースが後から増えるかもしれない
- inputなど引数はnot null、DBやネットワークなど失敗しうるデータがソースならnullable、などのように使い分けるとよい
- ミューテーションの粒度
- createは粗く、updateデータを細かく修正するユースケースが発生しやすいので細かく
- 内部APIなら特定のユースケース特化型のミューテーションを作ってもいい。トランザクションの問題も回避できる
- ミューテーションのエラーハンドリング
- GraphQLの
errors
キーで表現するエラーは技術的な例外を表す。ビジネスロジックの例外はスキーマ上で独自エラーとして表現する - ミューテーションの戻り値のペイロードで、独自エラーをユニオンやインタフェースを使って表現する
- GraphQLの
- 非同期処理
- ユニオンやenumでステータスを返すことで実行中であることを表現する
- Shopifyでは
Job
という型を導入している https://shopify.dev/docs/api/admin-graphql/2023-07/objects/job
サーバサイドの実装
サーバサイドの実装については"Implementing GraphQL Servers"で説明されている。おもしろかったのは次の点。
- スキーマファースト vs 実装ファーストという観点があるが、ハイブリッドな戦略をとるとよい
- SDL (Schema Definition Language)をもとに設計を議論
- 各言語のライブラリを使って、コードファーストで実装
- 最後にコードからSDLのアーティファクト(最終的なスキーマのSDL)を生成してコミットするのがよい
- リゾルバは薄く作ること
- 本質的に網羅的なテストが難しいが、次のような箇所をテストするとよい
- ある型のオブジェクトを返すフィールド、そオブジェクトの全フィールドを取得するテスト
- 認可などセキュリティ的に重要な箇所
感想
上述したようにスキーマの設計や実装だけでもさまざなトピックがある。パフォーマンスの観点ではお馴染みのDataLoaderが紹介されていたり、ツールの章ではリンタについての説明があったりと、開発の際に都度参照すると役に立ちそうな項目が多い本となっている。
まずは、スキーマの設計を検討するときのベースとして、今後はこの本で挙げられている項目を確認していこうと思う。
- なお、"One-Size-Fits-All"はREST APIの設計で発生しやすいものの、エンドポイントベースなAPIならどれでも起きる可能性があり、GraphQLはREST API自体を代替するものではないと再三いわれている↩