病みつきエンジニアブログ

機械学習、iPhoneアプリ、Javascript,Ruby on Railsなどなど。

「GraphQLは何に向いているか」に対してのちょっとした反論

k0kubun.hatenablog.com

非常に丁寧に書かれていると思うのですが、少し反論したい部分があるので、記載したいと思います。

GraphQLのキャッシュ効率について

クエリをパースしないとキャッシュの可否を判定できないため、HTTPキャッシュが難しい

こちらに関して、2つの観点から反論してみたいと思います。

まずに、GraphQL は GET リクエストでも送ることができます。Serving over HTTP | GraphQL によると、http://myapi/graphql?query={me{name}} のような URL の GET リクエストができます。(※そもそも、これ自体は GraphQL の絶対的な制約ではなく、 GraphQL を一般的に HTTP で提供するときのプラクティス、という位置づけです)

そして、GraphQL は 1 回のリクエストで送らなければならないわけではない、ということです。

私は JX 通信社 で NewsDigest というニュースアプリを作っています。例えばニュースアプリであれば、「フィード」というキャッシュ効率の高いものあれば、「ユーザーの設定」というキャッシュできないものや、書き込むものもあります。このような例であれば、キャッシュ効率の高いリクエストとキャッシュ効率の低いリクエストをわけ、さらに mutation の操作のみ POST リクエストを送れば、CDNなどでもキャッシュ可能です。

これは REST API であれば、 GET /feedGET /settingsPOST /settings というリクエストにわかれるわけですが、 GraphQL の方が特別キャッシュしづらいというわけではない のではないかと思います。(※もちろん、リクエストをわけると GraphQL のメリットは下がります)

弊社がGraphQLを採択してみた理由

厳密には採用したものをリリースしようとしている段階ですが、弊社で GraphQL を採用したかった理由を述べたいと思います。

GraphQL に感じる大きなメリットの1つは、API と型とドキュメントがパッケージ化されている ことです。もちろん、 JSON Schema や API Blueprint を組み合わせることもできます。しかし、これがパッケージ化されていて、「GraphQL」という技術の標準規格であり、後付けの技術ではないというのは大きなメリットだと思います。「GraphQLのドキュメント読んどいてください」「GraphiQL触ってください」で話せるわけです。

もう一つは、 GraphQL はクエリが定数であり、「どうリクエストするか」を定数化できる というところです。このメリットが触れられていることを見たことがないのですが、これは GraphQL にしか解決できない(?)大きなメリット だと思います。「定数化」というのはどういうことかというと、 { hoge { fuga, piyo } } みたいな「どのオブジェクトを取得し、このフィールドが必要である」という情報を「定数」として、AndroidiOSJavascript、サーバーサイドで共通化できる、ということです。例えば「アプリ立ち上げ時にはこのリクエストを送って下さい」という指示を、クエリ定数 として、各プロジェクトで共通化でき、サーバーサイドのスナップショットテストでクエリの互換性を担保したり、、、みたいなこともできます。

※ 「クエリを定数化」と書いてしまったのですが、クエリ自体が定数なので(その代わりに引数や変数の概念がある)、表現を修正しました

逆に、GithubFacebook のようにリソースが多かったり、サーバーサイド開発者がクライアント側を書いたりは(あまり)していません。

また、キャッシュ効率について「CDNでもキャッシュできる」とは述べたのですが、フィードのパーソナライゼーションなどが必要になるので、採用していません。

個人的に考えるGraphQLの大きな問題

クエリのパースが複雑なため、ライブラリ依存になる、という点です。

例えば、2017 年 9 月現在、 Python の GraphQL ライブラリには次のように書いてあります

This library is a port of graphql-js to Python and currently is up-to-date with release 0.6.0.

0.6.0 は 2016 年 5 月の実装です。「各言語ごとの GraphQL ライブラリが対応してないものには対応できない」という潜在的な問題を含んでいることになります。もちろん、OSS なので Contribute すれば良い、ということでもあるのですが。

もう一つ、一般的に HTTP 上の GraphQL のレスポンスはオブジェクト(連想配列)を返すので、でかい配列データ(ニュースフィードなど)を JSON Streaming でインクリメンタルに表示する、みたいなのが難しいんじゃないかなーと思ったりもします。

GraphQL を採択すべきでない理由をあげるなら

GraphQL は、あまり何かを制限するものではありません。 RESTful API のように使うことも一応可能です。

したがって、「GraphQLを使うべきでない」というケースというのは「RESTful API のような使い方ぐらいしかしないからオーバーエンジニアリングだ」というときなんじゃないでしょうか。

まとめ

  • GraphQL は何か制限をするものではない
  • GraphQL は型やAPIドキュメントをパッケージ化していて、クエリを定数として共有できるのもメリット
  • GraphQL が適さないケースは確かにあるが、キャッシュは問題ではないと考えている

GraphQL がもっと広まるとうれしいです。3 年後には「何だったのか」って総括されてそうですけど。笑

以上です。

補足

ブコメありがとうございます!

id:koyancya

定数クエリ、REST のエンドポイント増やすのとは何が違うのだろうか

ニュースアプリとかの場合を想定して、例えば、アプリの立ち上げ時に「トップのフィード」「ユーザー設定」を同時に読み込みたいとします。これはGraphQLでは次のように表現できます(※実際には引数や変数を宣言しますが、クエリ自体は定数です)。

GET /graphql

{
  feed {
    title, createdAt
  }
  setting {
    subscription, prefecture
  }
}

一方で、GraphQL でない場合、これを「定数」として縛ろうとすると、次のようなエンドポイントを生やす感じになってしまうかなと思います。

GET /app_startup

これでは、そもそも RESTful ではなくなってしまいます。また、「やっぱり立ち上げ時は、ユーザー設定読み込むのやめよう!」となったとき、API側を変更する必要が出てきてしまいます。GraphQL の場合、リソースを宣言してさえおけば、フロント側だけでリクエスト方法を固定できます。(で、答えになっていれば良いのですが・・・!)