@mizumotokのブログ

テクノロジー、投資、書評、映画、筋トレなどについて

GraphQLの要点が分かる!メリットとデメリット

GraphQLとはこれまでWeb APIの主流であったRESTの課題を克服するために生まれました。RESTの課題を克服したメリットは大きく徐々に広まってきています。一方で当然デメリットも存在します。この記事を読めばGraphQLの生まれた背景を知り、メリットとデメリットを理解できるようになります。

f:id:mizumotok:20210718205637p:plain

GraphQLとはWeb API

GraphQLとは

GraphQLとはWeb APIのための問い合わせ言語です。その問い合わせ言語を実装した実行環境のことを指すこともあります。
Web APIと言えばRESTが最も普及していますが、RESTにはほとんどの開発者が抱えるいくつかの課題があります。その課題を解決するために、GraphQLは誕生しました。
graphql.org

Web APIの歴史

RPC

遠隔地のシステムとデータ通信をするために、1960年代にリモートプロシージャコール(RPC)が発明されました。RPCプロトコルは微妙な違いをもった多くのバリエーション実装があり、それらの間には互換性がありません。標準化を目指して、XML-RPCJSON-RPC、gRPCといったRPCプロトコルが誕生しています。

SOAP

1999年、マイクロソフトによってSOAP(Simple Object Access Protocl、現在は「何かの頭字語ではない」とされている)が発表されました。SOAPXML-RPCの拡張で、HTTPプロトコル上でXML形式のメッセージを通信します。事前にAPI定義を公開したWSDLファイルによってモジュールの自動生成する等の特徴がありましたが、実装が複雑になりがちで、開発者にとってとっつきいくいものでした。

REST

REST(Representational State Transfer)はHTTPプロトコル規格の主要著者の一人であるロイ・フィールディング書いた2000年の博士論文で初めて現れ、すぐに広く使われることになりました。現在もっとも使用されているWeb APIと言っていいでしょう。

RESTはURIが情報に対応します。例えば次のエンドポイントにリクエストを送信すると、それぞれ固有のレスポンスを返します。

/api/people/1
/api/planets/3

RESTはデータモデル毎に多様なエンドポイントを提供し、これは既存の手法に比べて単純明快なことが人気を博しました。

当初はRESTはXMLと一緒に使われました。ウェブブラウザのJavaScript上でRESTを使って非同期通信を行う手法はAjax(Asynchronous JavaScript And XML)と名付けられ、Google Mapsに使用されたことで、広く普及することとなりました。JavascriptでのXMLのパースは苦痛であることから、現在ではJSONが使われることがほとんどです。

RESTの課題

Webが発達するにつれてRESTが適合しない状況が生じてきました。その状況に適合するAPIとして、GraphQLが誕生しました。

オーバーフェッチング

スターウォーズAPI(SWAPI)にはREST版とGraphQL版があります。
REST版スターウォーズAPIルーク・スカイウォーカーの情報(https://swapi.dev/api/people/1/)を取得すると以下のようになります。

{
	"name": "Luke Skywalker",
	"height": "172",
	"mass": "77",
	"hair_color": "blond",
	"skin_color": "fair",
	"eye_color": "blue",
	"birth_year": "19BBY",
	"gender": "male",
	"homeworld": "https://swapi.dev/api/planets/1/",
	"films": [
		"https://swapi.dev/api/films/2/",
		"https://swapi.dev/api/films/6/",
		"https://swapi.dev/api/films/3/",
		"https://swapi.dev/api/films/1/",
		"https://swapi.dev/api/films/7/"
	],
	"species": [
		"https://swapi.dev/api/species/1/"
	],
	"vehicles": [
		"https://swapi.dev/api/vehicles/14/",
		"https://swapi.dev/api/vehicles/30/"
	],
	"starships": [
		"https://swapi.dev/api/starships/12/",
		"https://swapi.dev/api/starships/22/"
	],
	"created": "2014-12-09T13:50:51.644000Z",
	"edited": "2014-12-20T21:17:56.891000Z",
	"url": "https://swapi.dev/api/people/1/"
}

ユースケースによっては名前と身長と性別だけかもしれません。この場合必要な情報はこうなります。

{
	"name": "Luke Skywalker",
	"height": "172",
	"gender": "male",
}

これ以外の情報は余分(オーバーフェッチング)なのです。
複数のユースケースに対応(one-size-fits-all、OSFA)しようと、レスポンスは大きくなりがちです。通信量が多くなりますし、サーバサイドでも例えばstarshipsの情報をとるために余計な負荷がかかることもあります。

アンダーフェチング

上記のSWAPIの例で取得した映画情報は次のようになっています。

	"films": [
		"https://swapi.dev/api/films/2/",
		"https://swapi.dev/api/films/6/",
		"https://swapi.dev/api/films/3/",
		"https://swapi.dev/api/films/1/",
		"https://swapi.dev/api/films/7/"
	],

映画名も一緒に表示しようとすると、これらのAPI(5個)をリクエストしないといけません。これはいわゆるN+1問題になります。

たくさんのエンドポイントの管理

オーバフェッチングやアンダーフェッチングを回避しようとするとユースケース毎にエンドポイントを作成することになります。またうまく複数のユースケースに対応(one-size-fits-all、OSFA)していたとしても、ある特定のユースケースで仕様変更を行うことになると、新規にエンドポイントを立ててバージョン管理する必要ができたり、クエリーを追加(例えば ?version=2?includes_film_name=true)してエンドポイントの仕様が複雑になっていくという問題が生じてきました。

GrapqhQLの特徴

GrapqQLの誕生

GraphQLは上記のRESTの課題を解決するために、Facebookによって生み出されました。
2015年に最初のGraphQLの仕様を公開し、Javascriptによる参照実装であるgraphql.jsを公開しました。今日では、Facebookのほぼすべてのサービスで利用され、IBMAirbnbGitHub、Shopifyを始めとした多くの企業で使われています。

GraphQLの設計原則

GraphQLは言語仕様であり、実装を規定していません。GraphQLのライブラリは言語仕様に従って、それぞれが独自に実装されています。
GraphQLを実装を規定はしていませんが、設計原則を掲げています。

  • 階層的:今日のほとんどの開発では、ビューでは階層構造のデータの作成と操作が行われています。このようなアプリケーションの構造と一致させるために、GraphQLのクエリ自体も階層構造になっています。クエリは、返されるデータと同じ形をしています。クライアントが必要なデータを自然に記述できるようになっています。
  • プロダクト中心:GraphQLは、ビューとそれを書くフロントエンドエンジニアの要求に忠実に従います。GraphQLは、彼らの考え方や要求を実現するために必要な言語やランタイムを構築します。
  • 強い型付け:すべてのGraphQLサーバーは、アプリケーション固有の型システムを備えており、クエリはその型システム上で実行されます。クエリが作られたときにツールを使うことで、実行前(=開発時)に、そのクエリにバリデーションをかけることができます。サーバーはレスポンスの型の形式を保証します。
  • クライアントごとのクエリ:GraphQLサーバーは、その型システムを通じて、クライアントが何のフィールドを取得できるかを公開します。それらをどのように利用するかを指定するのは、クライアント側の役割です。これらのクエリは、フィールド単位で指定されます。GraphQLのクエリは、クライアントが要求したデータだけ返し、それ以上は返しません。
  • 自己参照(Introspective):GraphQLサーバーは、サーバ自身の型システムを問い合らせられるようにできています。GraphQLのこの特徴は、ツールやライブラリを開発するのにとても役に立ちます。

GraphQLの例

先ほどのスターウォーズAPIの例をGraphQL版APIで試してみます。
ルーク・スカイウォーカーの名前と身長と性別と映画のタイトルだけを取得しようとすると以下のようなクエリを作成します。

query {
  person(personID: 1) {
    name
    mass
    gender
    filmConnection {
      films {
        title
      }
    }
  }
}

結果は以下のようになります。

{
  "data": {
    "person": {
      "name": "Luke Skywalker",
      "mass": 77,
      "gender": "male",
      "filmConnection": {
        "films": [
          {
            "title": "A New Hope"
          },
          {
            "title": "The Empire Strikes Back"
          },
          {
            "title": "Return of the Jedi"
          },
          {
            "title": "Revenge of the Sith"
          }
        ]
      }
    }
  }
}

指定した必要な情報だけを取得できており、オーバーフェッチングもアンダーフェッチングもありません。エンドポイントは常に一つであり、新しいユースケースでフィールド追加の要件があったとしても既存のクエリには影響しませんのでクエリのバージョン管理も不要です。

GrapqhQLのデメリット

見事にRESTの課題を克服したGraphQLですが、デメリットも存在します。
GraphQLは誕生からまだ6年しか立っておらず、20年の実績のあるRESTと比べると実績に乏しく、ノウハウが蓄積されていません。例えばキャッシュやパフォーマンス分析はRESTではエンドポイント毎に対応可能ですが、エンドポイントが一つのGraphQLではまだまだ試行錯誤の状況にあります。
また、クエリ言語はわかりやすいとは言え、RESTのURIと情報の操作が対応するという特徴に比べると、やや難しく感じられるかもしれません。

GrapqhQLのエコシステム

GraphQL登場から6年経過し、エコシステムも充実してきました。その中からよく使われるライブラリを紹介します。

Apollo GraphQL

Node.jsのGraphQLサーバとJavascriptクライアントがあります。特にこだわりがなかったらJavascriptクライアントはApolloで十分じゃないかと思っています。
www.apollographql.com

AppSync / Amplify

AWSのAppSyncはGraphQL APIのマネージドサービスです。DynamoDBのデータやLambdaで生成したデータをGraphQL APIで返すことができるようになります。
AmplifyはAppSyncを含め、サーバサイドのDynamoDBやLambdaをまとめてcliで作成したりコードで管理できたりして、クライアントアプリの開発に集中できるようにしてくれます。AWSのサービス群、特にサーバレス環境で爆速でクライアントアプリを作りたいという場合には非常に有用です。
aws.amazon.com

Hasura

PostgreSQLのデータから自動で型システムを構築してくれるGraphQLサーバです。ジョインも含めて、基本的なクエリなら自動でさくせしてくれるので、Amplifyと同様にクライアントアプリの開発に集中しやすくなります。認証機能もありますので、Firebase Authenticationと組み合わせて認証付きGraphQLサーバも簡単に実現できます。AWSのサーバレス環境でなく、RDBを使いたい場合には便利です。
hasura.io

GraphQL Ruby

GraphQLのruby実装です。Ruby on Railsに依存はしていませんが、Ruby on Rails環境に簡単に導入可能です。Node.js以外の言語では一番コミュニティが活発です。
graphql-ruby.org

Relay

GraphQLを発案したFacebookによるJavascriptクライアント実装です。Apollo Clientの競合です。私はApollo派ですが、Apolloは独自のステート管理を採用してreduxを排除したりしているので、ステート管理やキャッシュ管理を自分で行いたいような人はRelayの方が向いているかもしれません。
relay.dev

GraphQL Code Generator

GraphQLはサーバが用意したスキーマに沿って、クライアントを構築していくのですが、このスキーマからTypescriptの型定義やクエリからJavascriptの関数を自動生成してくれます。React hookを作ってくれる機能もあったり、何かと便利です。
www.graphql-code-generator.com

まとめ

  • GraphQLはWeb APIの新しい形です
  • 現在のWeb APIの主流であるRESTはオーバーフェッチング等の課題も多く、それらを克服するためにFacebookが開発しました
  • GraphQLはRESTはRESTに比べて歴史が浅く、出回っている知見も少ないですが、徐々にエコシステムやノウハウ共有が進んできています