技術とかの雑なToday I Learnedメモ

React 時代に選ぶ GraphQL を読んだ

React 時代に選ぶ GraphQL を読んだ

React 時代に選ぶ GraphQL - とろろこんぶろぐ

読んだ。

GraphQL は使ったことがないのだけどこの記事を読んでどういうものなのか概要が理解できてよかった。

記事内では UI の複雑化により必要な情報を API から取得することについて詳しく書かれていた。

UI が複雑化してきており、1画面につき1つの URL を叩けばいいというわけではなくなってきている。1つの操作や1つのコンテキストにつき1つの URL という考え方をしたほうが、その複雑性によりメンテナブルに対処できる場合がある。

コンポーネントベースの設計を行うことで、よりメンテナビリティの高いアプリケーションの開発ができる。ただ、コンポーネントベースの設計は UI の設計であり、 DB のデータ構造とは関係のない設計になる。そして RESTful な API の場合は、画面に必要な情報を取得するために、1つの画面から複数の API を叩いて情報を取得する必要がある。複数の API 呼び出しが必要なので、データの被りが発生したり必要でないデータも同時に取得してしまうなど、ネットワークコストが発生する。

そこで、この記事では1つのページに対してそのページに必要なデータを過不足なく返すための API (記事内ではページ API) を作る話がある。ただ、この方法だとサービスの拡張性が低いとも書いてある。

極端な例で言うと、全ての画面でヘッダーコンポーネントを共通で利用しているとします。 ヘッダーに新たに API から取得したキャンペーン情報を載せたい場合、 1 画面 1 API で構築されていたら全画面向けのページ API にキャンペーン情報を新たにアグリゲーションする変更を加える必要があります。

なるほど。

1コンポーネント1 API とする方法もある。ただ、これも弱点があり、コンポーネントの粒度がバラバラだと API の粒度もバラバラになる。

どの粒度以上のコンポーネントには API を用意し、どの粒度以下のコンポーネントには用意しないのか、ルールの定義が難しく保守性の観点でデメリットがあります。

さらに、1 画面内に配置された複数のコンポーネントで同じデータを使うことがあり得るため、同じデータを重複して取得し、重複して保持することになります。

こんな感じでデメリットのほうが大きそう。

ユースケースごとの API の説明があったところで、以下のような説明がある。

GraphQL は極端に言うと、バックエンド側では /graphql という一つのエンドポイント API だけ開発すれば良く、バックエンド側でユースケースを意識する必要はありません。 実際には GraphQL のリゾルバで API でデータ呼び出しを行います。

GraphQL で改めて Schema を定義しておくことで、 UI で Schema として定義したプロパティを自由に組み合わせて呼び出すことができます。 UI 側、つまり UI コンポーネントでは必要なデータを必要な場所でクエリとして定義します。 これは Fragment Colocation と呼ばれます。 個々のコンポーネントで必要なデータを取得する部分的なクエリ(Fragment)を、コンポーネントに近い場所へ配置する(Colocation)ものです。

コンポーネントに必要なデータだけを必要なクエリとして定義することができ、かつデータの重複がおきないようにできる旨が書いてある。

例えば GraphQL の Relay というライブラリでは、コンポーネントごとに定義したクエリを実際にページから呼び出す際に 1 つの大きなクエリにアグリゲーションした上で重複を排除して呼び出す仕組みがデフォルトで機能に含まれています。

このような観点から、コンポーネントベースの設計では GraphQL を使うことがメリットになる。

今後は Nested Layout の RFC が登場し、 GraphQL で実現できていたことが Next.js でも近いことができるようになります。 これまで Next.js の画面遷移は、異なるページへの遷移時に画面に必要なデータ、コンポーネントを全て取得し直す形になっていました。 Nested Layout は名の通り Layout を入れ子に定義できるものになります。 これにより画面上の遷移や操作時に必要最低限のコンポーネントを UI 上で変化させることができるようになります。 つまり、コンポーネント API 的な API を不要に呼び出してしまうことはなくなります。

閑話休題の Next.js の部分についてだけど、 Nested Layout のメリットはなんだろうと考えた。

前の例で「すべてのページに必ずヘッダーが表示される」というのを考えると、ヘッダーを表示するレイアウトコンポーネントを作っておけば毎度ヘッダーがレンダリングされることがない(= それ以外の変化が必要な部分の UI が変化する)とかなのかな?

変化前のページと変化後のページで必要なデータが被っている場合はその部分だけ再取得せず使い回せるみたいな感じなのだろうか。

その他メリットについて書いてあるが、

  • ユーザーが求める UI は日々変わっていき、複雑でリッチな UI が求められる。これに対してアジリティ高く改善していくためにフロントエンドチームのみで改善をリリースできるようにする。
  • UI 側のクエリ定義だけで取得するデータを変化させられるので API 側に手を入れる必要がなく、フロントエンドのリリースサイクルをより速く回せる
  • 型の生成はあらかじめ Schema を定義しておくことでリゾルバとクエリの型を自動生成できる
  • クライアントによってバックエンドを用意する必要がなく修正も必要ないため、クライアント側の変更に強い

ということが書いてある。

また、

GraphQL が使われている記事やサンプルコードが RESTful API が使われているものより少ないというようなことは、重要な問題ではありません。 ライブラリやフレームワークの信頼性や保守性が高いコードであることの方が重要です。

複雑性の高い UI 要件をメンテナブルな状態で維持するためには、保守性高く設計する必要があります。 言うまでもなくこれにはフロントエンドに精通した技術力が必要です。

「リッチで複雑な UI 要件にはしたいが、 GraphQL を使えるほど優秀なエンジニアがいない」状態なら、 GraphQL を選ばない選択をするのではなく UI 要件を削り簡素なものにする選択をすべきです。

といったことも書かれている。

GraphQL の魅力は非常に伝わったので、注意深く考えながら導入を考慮したい。