GraphQLとRelay
このセクションでは、GraphQL、React、およびスタックの他の部分との関係においてRelayを位置づける概要を説明します。すべての詳細を理解しようとせず、要点を把握して次のセクションに進み、コードを扱い始めてください。チュートリアルを通して作業例を見ていくうちに、より具体的な内容が説明されます。
GraphQLは、サーバー上のデータをクエリおよび変更するための言語です。GraphQLのユニークな点は、固定されたAPIエンドポイントのセットを持つのではなく、サーバーがクライアントが必要とするデータの任意の組み合わせを要求するために使用できるオプションのパレットを提供することです。これにより、フロントエンドの開発者は、データ要件が変更されたときに新しいエンドポイントを作成およびデプロイする必要がないため、より迅速に作業を進めることができます。また、クライアントの新しいバージョンがリリースされたときに、古いバージョンとの互換性のために残った余分なフィールドなしに、必要なデータのみを要求できることも意味します。
GraphQLは、あらゆる種類のバックエンドにわたってデータをクエリするための統合インターフェースを提供します。データがリレーショナルSQLデータベース、グラフ指向データベース、またはマイクロサービスの艦隊にあるかどうかに関わらず、GraphQLサーバーは複数のバックエンドからデータを収集し、単一のレスポンスでクライアントに送信できます。これは、クライアントから各サービスに個別のクエリを発行するよりも効率的です。
従来のHTTP APIでは、それぞれが固定された情報セットを返すURLがあります
Request:
GET /person?id=24601
Response:
{"id": "24601", "name": "Jean Valjean", "age": 64, "occupation": "Mayor"}
GraphQLでは、クライアントは必要な特定の情報を要求し、サーバーは要求された情報のみを返します
Request:
query {
person(id: "24601") {
name
occupation
}
}
Response:
{
"person": {
"name": "Jean Valjean",
"occupation": "Mayor"
}
}
クライアントが要求した特定のフィールドのみがレスポンスに含まれていることに注目してください。
名前が示すように、GraphQLはデータをグラフに整理します。グラフは、ノード(オブジェクトやレコードのようなもの)とエッジ(あるノードから別のノードへのポインタ)で構成されます
GraphQLでは、あるノードから別のノードへエッジをたどり、訪問する各ノードに関する情報を要求できます。たとえば、ここでは人から都市に行き、都市に関する情報を取得します
- リクエスト
- レスポンス
query {
person(id: "24601") {
name
occupation
location {
name
population
}
}
}
{
"person": {
"name": "Jean Valjean",
"occupation": "Mayor",
"location": {
"name": "Montreuil-sur-Mer",
"population": 1935
}
}
}
これは、1つのクエリですべてのオブジェクトに関する情報を取得できることを意味します。つまり、UIの各画面に別々のエンドポイントを作成して維持するのではなく、1つのリクエストで画面のすべてのデータを効率的に取得できます。
代わりに、GraphQLサーバーは、どのような種類のノードがあるか、それらがどのように接続されているか、各ノードにどのような情報が含まれているかを記述したスキーマを提供します。次に、このスキーマから選択して、必要な情報を選択します。
このチュートリアルのサンプルアプリはニュースフィードアプリであるため、そのスキーマは次のような型で構成されます。
- ニュースフィードストーリーを表す
Story
- タイトル、画像、投稿した人または組織へのエッジなどのフィールドがあります - 名前、メール、友達のリスト(他のPersonへのエッジ)などの情報を持つ
Person
。 - アプリを見ている人を表し、ニュースフィードストーリーのリストなどの情報を持つ
Viewer
- 画像自体のURLと
alt
テキストの説明を持つImage
。
GraphQL言語には、スキーマを指定するための型システムと言語が含まれています。これは、サンプルアプリのスキーマ定義からのスニペットです。すべての詳細を気にする必要はありません。一般的なアイデアを示すためのものです
// A newsfeed story. It has fields, some of which are scalars (e.g. strings
// and numbers) and some that are edges that point to other nodes in the graph,
// such as the 'thumbnail' and 'poster' fields:
type Story {
id: ID!
category: Category
title: String
summary: String
thumbnail: Image
poster: Actor
}
// An Actor is an entity that can do something on the site. This is an
// interface that multiple different types can implement, in this case
// Person and Organization:
interface Actor {
id: ID!
name: String
profilePicture: Image
}
// This is a specific type that implements that interface:
type Person implements Actor {
id: ID!
name: String
email: String
profilePicture: Image
location: Location
}
// The schema also lets you define enums, such as the category
// of a newsfeed story:
enum Category {
EDUCATION
NEWS
COOKING
}
クエリに加えて、GraphQLではサーバーにデータの更新を要求するミューテーションを送信することもできます。クエリがHTTP GETリクエストに類似している場合、ミューテーションはPOSTリクエストに相当します。POSTと同様に、サーバーが更新されたデータで応答できるようにします。GraphQLには、リアルタイム更新のためのオープンな接続を可能にするサブスクリプションもあります。
(GraphQLは通常HTTP上で実装されているため、クエリとミューテーションはGETとPOSTに類似しているだけでなく、そのように送信される場合もあります。)
GraphQLについて説明したので、次にRelayについて説明しましょう。コードに飛び込む前に、簡単に説明するいくつかの異なる部分があります。
Relayは、GraphQLを中心に据えたクライアント用のデータ管理ライブラリですが、GraphQLを最大限に活用する非常に特定の方法で使用します。
最高のパフォーマンスを得るには、各コンポーネントが独自のリクエストを発行するのではなく、各画面またはページの最初に単一のリクエストを発行するようにアプリを作成する必要があります。しかし、それの問題点は、コンポーネントと画面が結合され、大きなメンテナンス問題が発生することです。特定のコンポーネントで追加のデータが必要な場合は、そのコンポーネントが使用されているすべての画面を見つけて、その画面のクエリに新しいフィールドを追加する必要があります。一方、特定のフィールドの必要性がなくなった場合は、すべてのクエリからそのフィールドを削除する必要があります。しかし、今度は、そのフィールドが他のコンポーネントで使用されていないことを確認する必要がありますか?これらの大きな画面全体のクエリを維持することは非常に困難になります。
Relayのユニークな強みは、各コンポーネントがローカルで独自のデータ要件を宣言できるようにし、それらの要件をより大きなクエリにまとめることで、このトレードオフを回避することです。そうすることで、パフォーマンスと保守性の両方を実現できます。
Relayは、JavaScriptコードをスキャンしてGraphQLのフラグメントを見つけ、それらのフラグメントを完全なクエリにまとめるコンパイラを使用してこれを行います。
コンパイラに加えて、RelayにはGraphQLのフェッチと処理を管理するランタイムコードがあります。取得されたすべてのデータ(Storeと呼ばれる)のローカルキャッシュを維持し、各コンポーネントに属するデータを販売します
集中型Storeを持つことの利点は、データが更新されたときにデータを一貫性を保つことができることです。たとえば、UIに誰かが自分の名前を編集する方法がある場合、1つの場所でその更新を行うことができ、その人の名前を表示するすべてのコンポーネントが新しい情報を表示します。それらが異なる画面にあり、したがって最初にデータを取得するために異なるクエリを使用したとしてもです。これは、Relayがデータを取り込む際にデータを正規化するからです。つまり、単一のグラフノードに対して表示するすべてのデータを1つの場所にマージするため、同じノードの複数のコピーを持つことはありません。
実際、Relayはデータをクエリするだけでなく、楽観的な更新やロールバックのサポートを含め、クエリと更新のライフサイクル全体に対応します。ページネーション、データの更新など、UIの作成に必要なすべての基本操作を実行できます。Store内のデータが更新されると、Relayはその特定のデータを表示しているコンポーネントのみを効率的に再レンダリングします。
まとめ
GraphQLは、データをグラフとしてモデル化し、サーバーからそのデータをクエリ(およびデータの更新)するための言語です。Relayは、各Reactコンポーネントと同じ場所に配置された個々のフラグメントからクエリを構築できる、ReactベースのGraphQL用クライアントライブラリです。データのクエリが完了すると、Relayは一貫性を維持し、データが更新されるとコンポーネントを再レンダリングします。