GraphQLは、1回のAPI呼び出しで複数のソースからデータを取得できる、API向けのオープンソースクエリ言語です。また、既存のデータを使用してクエリを処理するサーバー側ランタイムとしても機能します。GraphQLは、APIデータの完全な記述を提供しながら、要求されたデータのみをクライアントに返すことを重視しており、APIの拡張や進化を容易にします。

GraphQLを理解する

GraphQLは、柔軟性、スピード、開発者を重視して設計されています。GraphQLを使用すると、開発者はニーズに応じてAPIを構築し、GraphQL仕様に基づいて、そのAPIがクライアントで機能することを確認できます。

GraphQLクエリの主要な概念の1つは、返されるデータを予測できることです。余分なコードの羅列ではなく、要求したデータだけが返されます。この宣言的なデータ取得は、帯域幅が限られるモバイルデバイスで特に有用です。また、GraphQLを使用するアプリでは、サーバーではなくアプリ側で要求および受信するデータを制御するため、安定性と速度が向上します。1回のリクエストで要求した複数の項目をまとめて取得できるため、低速なネットワーク接続でも高速に動作します。

GraphQLによるデータの簡素化をさらに進め、APIはエンドポイントではなく型とフィールドで構成されます。これにより、すべてのデータに単一のエンドポイントからアクセスでき、アプリは必要なデータだけをリクエストできます。運用の複雑さを軽減するGraphQLは、効率化されたAPI接続ソリューションのワークフローに適しています。

略史

2012年、Meta(当時のFacebook)は、Facebookのモバイルアプリケーションに十分対応できる高性能なデータ取得APIを必要としていました。Lee Byronの主導のもと、Facebookは、特にプロダクトデザイナーや開発者の視点からデータ取得を簡素化する手段としてGraphQLを開発しました。GraphQLは当初Facebook社内で使用され、その後2015年に一般公開され、オープンソース化されました。多くのオープンソースプロジェクトと同様の道をたどり、2019年にはGraphQLプロジェクトが独自のGraphQL Foundationに移管され、Linux Foundationの傘下となりました。

GraphQLは、RESTアーキテクチャに代わるものとして設計されました。標準的なREST APIでは、複数のURLから個別のHTTP GETリクエストを介して情報を読み込む必要があります。GraphQL APIでは、1回のPOSTリクエストですべてのデータを取得します。RESTとGraphQLはいずれもJSON形式のレスポンスを返しますが、GraphQLはデータ取得の効率化と一元化に重点を置いています。

GraphQLの仕組み

GraphQLはきめ細かなデータリクエストに対応し、送信される情報をクライアント側でより細かく制御できます。クライアントがGraphQLクエリをPOSTリクエストとして送信すると、サーバーはJSON形式のレスポンスを返します。GraphQLは特定のアプリケーションアーキテクチャを必要とせず、統合開発環境[IDE]を含む複数の環境にデプロイでき、既存のAPI管理ツールと併用したり、既存のREST API上で使用したりできます。

GraphQLの主な用語には、次のものがあります。

  • スキーマ – API開発者が、クライアントがクエリできるデータを示すために作成します。スキーマはオブジェクト型で構成され、クライアントがリクエストできる内容と、オブジェクトの特性を表すフィールドを定義します。
  • クエリ – クエリは検証された後、スキーマに基づいて実行されます。GraphQLでは、オブジェクト型を定義しないとクエリを実行できません。
  • Resolver – 各スキーマフィールドに関連付けられたResolver関数は、APIの実行時に呼び出され、値を生成します。Resolverは、GraphQLのアーキテクチャにおける重要なコンポーネントです。

GraphQLの特徴の1つは、レスポンスがクエリ(クエリ自体はスキーマで定義されます)の構造を反映することです。サーバーから返されるレスポンスの形式を完全に予測できるため、クライアント側での解析が容易になります。

設計

GraphQLは階層構造を持ち、オブジェクト間の関係に沿って処理するため、階層型のユーザーインターフェースに適しています。また、強い型付けを採用しており、クエリの各階層が型に対応します。各型では、一連のフィールドが定義されます。これはSQLと同様で、クエリの完了前に詳細なエラーメッセージが表示されます。

リゾルバーをデータソースに接続

リゾルバーは、GraphQLのフィールド、エッジ、ミューテーション、クエリ、サブスクリプションをデータソース(およびマイクロサービス)に接続する、アーキテクチャ上の主要なモジュールです。

AWSデータソース用のリゾルバーを構築する方法については、こちらのGraphQLチュートリアルをご覧ください。

取得する内容の指定

GraphQLクエリの特徴の1つは、レスポンスがクエリを反映することです。クエリから返されるデータはAPIリクエストと同じ構造になるため、予測可能です。返されるデータの構造がクライアントのクエリに従うことで、サーバーを簡素化できます。

GraphQLのメリット

GraphQLの大きな利点の1つは、RESTでは利用できない機能を提供する拡張機能が用意されていることです。GraphQLには、ほかにも次のような利点があります。

信頼できる唯一の情報源を確立

GraphQLスキーマは、GraphQLアプリケーションにおける信頼できる唯一の情報源となり、すべてのデータを記述する中心的な場所を提供します。GraphQLスキーマは通常サーバー側で定義されますが、クライアントはそのスキーマに基づいてデータのクエリや書き込みを行うことができます。

オーバーフェッチなし

RESTアーキテクチャでは、オーバーフェッチがすぐに問題となる可能性があります。アプリケーション(バックエンド)は各リソースで利用可能なデータを定義し、クライアント(フロントエンド)が必要とする要素が1つだけでも、レスポンスですべてのデータを返します。GraphQLでは、1回の呼び出しで、オーバーフェッチすることなく、クライアントが要求したデータを返します。

クライアントとサーバー間の通信を改善

データ型が厳密に定義されているため、GraphQLではRESTよりもクライアントとサーバー間の通信が明確です。また、この基盤構造により、GraphQLサーバーを呼び出すために複雑なクライアントは必要ありません。詳細と実際のコード例については、GraphQLの公式ページでクライアントとサーバーに関する説明をご覧ください。

Federationによるスケーラビリティ

API Federationは、一連の設計原則とツールで構成され、境界付けられたコンテキスト内のサービスを一貫したAPIとしてユーザーに公開しながら、そのコンテキスト内のサービスを制約なく進化させることを可能にします。GraphQLでは、既存のクエリを損なうことなくAPI全体をフェデレーションし、進化させることができるため、スケーラビリティを確保できます。このスケーラビリティが、多くの企業でGraphQLが採用されている理由の1つです。

イントロスペクション

GraphQLのイントロスペクション機能により、GraphQL APIからGraphQLスキーマを取得できます。クライアントは利用可能なデータ型の一覧もリクエストできるため、ドキュメントの自動生成や、複数のマイクロサービスに対するテストおよびスキーマ取得に最適です。

GraphQLのデメリット

GraphQLを採用する理由は数多くありますが、注意すべきデメリットもいくつかあります。たとえば、すべての機能をそのまま利用できるわけではなく、他者が提供するAPIを利用するには専用のライブラリが必要です。また、全体として、GraphQLはRESTよりも充実したツールサポートを必要とします。

RESTと比較したGraphQLのデメリットには、次のようなものがあります。

学習曲線

REST APIに慣れた開発者にとって、GraphQLの習得難易度は高くなります。また、ワークフローが変わる可能性もあります。GraphQLを使用するAPIチームは、保守しやすいGraphQLスキーマも作成する必要があります。ただし、ゼロから始める場合は、リクエストとレスポンスの構造が同じであるため、GraphQLは容易に習得して使用できます。

独自のAPI管理戦略

GraphQLでは新たなAPI管理戦略が必要になる可能性がある一方、REST APIは既存のAPI管理モデルに適合する傾向があります。新たなAPI管理戦略を追加すると全体的なコストが増加する可能性があるため、この点を考慮することが重要です。

複雑なキャッシュ処理

GraphQLのキャッシュは、通常HTTPメソッド(GET、POST、PUT、DELETE)を使用してリクエストするRESTほど単純ではありません。標準的なGraphQLリクエストではPOSTを使用しますが、HTTPレベルではキャッシュできません。また、GraphQLでは単一のエンドポイントを使用するため、そのエンドポイントのURLからキャッシュできないさまざまなレスポンスが返され、キャッシュが複雑になることがあります(データ取得には適していますが、キャッシュには不向きです)。その結果、サーバー開発者は、同じオブジェクト内で動作するクエリであっても、クエリごとに異なる処理を行うことになります。とはいえ、多くのGraphQLライブラリには、キャッシュ機構が標準で用意されています。