「初めてのGraphQL」を読んでGraphQLの概要を学んだ
オライリーの「初めてのGraphQL」を読んだ
先日の三連休中にオライリーの初めてのGraphQLを読んだ。入門書として内容がよくまとまっている上に、翻訳がとても読みやすく理解が捗った。GraphQL は個人開発で使いたいと思って何度かトライしたが、ネット上の入門記事やチュートリアルをいくつか読んで何度試してみても、腑に落ちたという感覚がどうにも得られなかった。
しかし、この書籍を通して GraphQL のクエリの書き方、Query、Mutation の区別、Subscription の位置付けと実装方法、リゾルバの役割、認可やファイルアップロードといった実践的な機能の実装方法を理解できた。
本書のサンプルコードは JavaScript で記述されている。また、サンプルアプリは Apollo が作っているライブラリ(apollo-client、apollo-server)と React を使って実装していることから、実際に使ってみるイメージが湧きやすかった。
ただし、翻訳の出版が2019年11月であり、サンプルコードでは React Hooks が使われていないのでその辺りは最新の書き方に読み替える必要がある。が、その辺りは本書を読むにあたり足枷には全くならない。
GraphQL に対して漠然とした苦手意識があった
個人的な話を書くと、以前は個人ブログをGastby で作っていたため GraphiQL を使って Query を書くことはできた。フロントで欲しい値はその Query をコピペして custom hooks で使えばよかった。
ただし、まだ GraphQL を理解したと言えない気がしたので Next.js の自分の実験用の Playground のサイトで GraphQL の公開エンドポイントからポケモンを取得する処理を書いてみた。 これで Query はわかった。
しかし、Mutation、Subscription、リゾルバに対する理解が不足していた。そこで、ネット上のチュートリアルの記事を読みながら apollo-server を使ってリゾルバを実装してみた。DB を使わずインメモリで配列を保持し、それに対して簡単な CRUD ができる TODO アプリを手元で作ってみた。
その際、graphql-codegen が便利だという話を聞いていたので、GraphQL Code Generator で TypeScript の型を自動生成する という記事を読みながらスキーマを書いてフロントのコードを自動生成してみた。この頃は、個人開発で自分が実際に使えるかの検証目的だった。
コードを自動生成できて簡単だったものの、認可の処理方法がわからなかったことやリゾルバを書いていても「これで本当に合ってるのか?」と疑念を晴らすことができなかったことから、本書を手に取るに至った。なお、この段階では個人開発での GraphQL の採用は見送って Supabase を使うことにした。
書籍を読むことで頭がクリアになった
本当は GraphQL のドキュメントを読めば済むのだろうが、概要をさっと掴むなら書籍の方がいいと思ってオライリーの初めてのGraphQL を買ったみた。それが数ヶ月前。ただ、個人開発の方を進めていたことと本業では REST API で開発していたことから外部要因で学習を迫られることがなく、ずっと積ん読をしていた。
しかし、やはり周囲から「GraphQL でフロントの記述が楽になる」と聞いて、連休中に重い腰を上げて読んでみた。結論から書くとこれが正解で、自分の知りたかったことが書いているし、俯瞰したようにスキーマ・クエリ、リゾルバその他を見渡せる感覚を得た。この書籍が自分の理解に足りていないピースをはめ込んでくれたのだった。このため、記事に残しておこうと思ったのだ。
以下では、自分の GraphQL に対する理解がクリアになった文をいくつか引用する。書籍の雰囲気は伝わらないかもしれないが、「結局、GraphQL って何?」という疑問にはいくらか答えてくれるはずだ。
GraphQL の紹介
GraphQL の言語仕様 は型システムと型システムに基づいたクエリの実行とバリデーションも規定していま す。しかしそれ以外には何も規定していません。
すべての GraphQL スキーマの核になるのは型です。GraphQL において、型は固有の オブジェクトで、アプリケーションの特性を反映します。
スキーマファーストは設計の方法論です。スキーマファーストではアプリケーション を作成するチームメンバー全員がデータ型について理解しています。(中略) スキーマファーストではすべてのチームメンバーがデータ 型を共通言語にして開発にまつわるコミュニュケーションを取ることができます。
GraphQLプロジェクトの肝はスキーマをうまく設計することです。よくできた GraphQL のスキーマはフロントエンドとバックエンドチームの間のロードマップと契約 として機能し、ビルドされた製品が常にスキーマに対応することを保証します。
仕組み
GraphQL はこの抽象構文木を走査することで、GraphQL の言語仕様とスキーマに対 してバリデーションできます。構文が正しく、クエリに含まれるそれぞれのフィールド や型がスキーマと一致していれば、処理が実行されます。バリデーションで何らかの エラーが発生すると、処理は実行されません。
もし本当に新しい Web の利点を生かしたければ、GraphQL は HTTP リクエ ストだけでなく WebSocket を使用したリアルタイムデータ通信をサポートできなければ いけません。その手段がサブスクリプションです。
定義
スキーマ
スキーマは型定義の集合です。
サブスクリプションのスキーマは PubSub デザインパターンの リアルタイムの通信を実装している必要があります。
クエリ
ミューテーションとクエリのスキーマ定義に仕様的な差はありません。両者は目的が異なります。
フラグメントは複数の場所で使いまわすことができる選択セットです。
ミューテーションはアプリケーションで使われる動詞と対応づくのが望ましいです。 サービスに対してできることがミューテーションとして定義されます。GraphQL のサー ビスを設計するとき、ユーザーが実行できる操作をすべて列挙してください。それがス キーマに定義するべきミューテーションです。
型
GraphQL にはスカラー型とオブジェクト型が存在します。(中略) GraphQL では 5 つのスカラー型が用意されています。整数型(Int)、浮 動 小 数 点 数 型( F l o a t )、 文 字 列 型( S t r i n g )、 論 理 型( B o o l e a n )、 I D 型( I D )で す 。(中略) GraphQL のオブジェクト型は、ひとつ以上のスキーマで定義されているフィールド の集合で、返される JSON オブジェクトの形を規定します。
グラフ理論
カスタムオブジェクト型のフィールドを定義することは、2 つのオブジェクトを接続 することにほかなりません。グラフ理論の言葉では、この接続部分はエッジと呼ばれる のでした。
リゾルバ
リゾルバは特定のフィールドのデータを返す関数です。リゾルバ関数はスキーマで指定されたとおりのデータを返します。リゾルバは非同期で処理することができ、REST API、データベース、その他のサービスからデータを取得したり更新したりできます。
リゾルバは単なる関数であり、GraphQL スキーマのすべてのフィールドをリゾルバにマッピングできます。
コンテキスト
コンテキストはどのリゾルバもアクセスできるグローバルな値を格納できる場所です。コンテキストは、認証情報、データ ベースの詳細、ローカルデータキャッシュ、その他 GraphQL オペレーションのために 必要なものを保管するのに適した場所です。
実践に向けた Tips
可能であれば、GraphQL のサービスは無向グラフにしておくことが望ましいです。 無向グラフにしておくことで、クライアントは非常に自由度の高い問い合わせができる ようになります。任意のノードを起点にしてほかのノードを接続していけるからです。
一般論としては、含まれている複数の型がまったく異なるものであれば ユニオン型を利用するのがよいでしょう。同様に、複数の型に共通のフィールドがある 場合はインターフェースを利用するほうがよいでしょう。
主要な用語は以下のようなもの。順番は思いついた順。
ルートリゾルバ、カスタムリゾルバ、トリビアルリゾルバ、enum、インターフェース、フラグメント、インラインフラグメント、Query、Mutaion、Subscription、スルー型、入力型、カスタムスカラー型、無向グラフ、有向グラフ、ノード、エッジ、グラフ理論
実装の章から定義の章に遡って読んだ
最後に少しだけ、本書を読んだ方法を書き残しておく。
自分は GraphQL に対する部分的な理解があったので、サンプルアプリを実装する第5章から第7章を先に読み、スキーマの設計の4章、GraphQL のクエリを紹介する3章、グラフ理論を解説する2章と遡って読んでいった。
これはどこにも書かれていない Tips なのだが、ある対象を体系立てて説明しているちゃんとした書籍では、前半で定義・解説した概念・用語を後半で活用する。その際、概念・用語が書籍内で初出の前半部分より、実はそれが2回目以降に登場する後半の方がシンプルな説明であることが一般的だ。
これはある概念や用語が書籍内で初出の段階では、なるべく包括的な解説をしようと言葉を費やして著者が丁寧に語ってくれるからである。一方、既に読者がなんとなくその用語や概念を聞きかじっている場合、得てして章の後半で登場する再定義の方が理解・暗記しやすい場合が多い。
このため、最初の解説は自分の知識の抜け漏れ防止のために、後半で出てくる再定義は自分用の簡潔な理解と、人に「AはXである」と伝えるための暗記用に使うと良い。例えば、上の引用のリゾルバの定義は明らかに後者の方が説明がシンプルだ。
今回はまさに「GraphQL を聞きかじった状態」だったため、自分が一番知りたい実装の章から読んでいった。そこで驚いたと同時に面白いと感じたことは、「前半では言葉を尽くして説明してくれたんだろうな」と思える用語のシンプルな再定義が、自分の抜けていた知識・理解の穴を埋めてくれたことだった。これは全く意外だった。
結局、個々の要素はなんとなく知っていても全体像が掴めていなかったのだ。コードを読んで手を動かすことは初めの一歩ではあるが、その実装は全体の中の部分でしかなく、全体の中での位置付けや担っている役割を知っておかないと真に理解したとは言えないのだ。
そして、知らないことを知っているという無知の知は自省だけでは得づらく、読書という著者との対話を通してやっと知らなかったところを知れる。これは一年を通してみても何度もあることではない。今回は良い体験ができた。
まとめ
正直なところ、書籍の紹介は読むのは好きだが自分で書くのは苦手だ。苦手なのだが、初めてのGraphQL のおかげでなんとなく感じていた苦手意識を払拭できたので紹介したいと思って記事を書いてみた。
これからは GraphQL の勉強会にも参加したり、Supabase を使っている個人開発でも自前でリゾルバを書いて段階的に取り入れてみようと思う。Supabase が作っている PostgreSQL の GraphQL extension が Stable になるのが待ち遠しい。
Happy Coding 🎉