Skip to content

Instantly share code, notes, and snippets.

@tkdn
Created August 30, 2018 04:23
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tkdn/75a4d7e38c2edb07b41da078e4a4aa11 to your computer and use it in GitHub Desktop.
Save tkdn/75a4d7e38c2edb07b41da078e4a4aa11 to your computer and use it in GitHub Desktop.
GraphQL について知っておきべく事

以下、記事の要約と個人的な疑問点などです。 GraphQL: Everything You Need to Know – Weblab Technology – Medium

また記事中に出てくるサンプルについてはより削ぎ落としたもので、依存がほとんどない。 GraphQL はクライアントからすると、クライアントキャッシングやその他課題はあるものの、クエリ言語である以外何者でもなさそうというがよく分かる。


GraphQL についてまず知っておきべきこと

REST API ほかこれまでの API テクノロジーとアプローチがどう違うのか。 GraphQL に関する賛否両論についてと主要な特徴についてまとめる。

GraphQL はフロントエンドデベロッパーがこれまで以上に簡単にデータをリクエスト出来るようにするため、とフロントエンド向けの文脈で通常説明されることが多い。Facebook によって開発されたこのクエリ言語の目的は、直感的かつスケーリング可能な形で作られたクライアントアプリケーションを作成し、データの前提要件をインタラクション(クライアントとのコミュニケーション)と同じように表現すること。特定のデータベースに依存しておらず、現時点のデータとコーディングによってサポートされている。

従来の REST API における一般的な問題として、クライアントがパーソナライズ(ここではプラットフォーム毎のという意味)されたデータセットをリクエスト出来ないという点が挙げられる。さらに複数のエンドポイントを実行・制御するということ自体、クライアントサイドが多様なエンドポイントから提供されるデータをリクエストする必要があるという点で、もう一つの難点となっている。

GraphQL サーバを新設する場合、完全なデータを取得したり変更したりするために単一のURLを持つことが重要。つまり利用者は必要なものを指し示すクエリストリングを転送することでサーバーにデータセットをリクエストすることが出来る。

GraphQL vs REST

当然だが、両方共 API 構築の手段として利用され、いずれも HTTP 経由でマネージドされてる。 違いといえば、REST はそもそもネットワーク中心のソフトウェアのための構築概念をであり、特定の仕様はなくツールセットも定義されているわけではない。パフォーマンスの最適化よりも API としての耐久性に重きを置いている。

一方、GraphQL は HTTP 経由での単一エンドポイントをさばいて、パフォーマンスと適用性に重きをおいたクエリ言語で、顕著な違いは以下の通り。

データフェッチ

データフェッチングは GraphQL によってもたらされた最も魅力的な進歩とも言える。通常の REST API はデータを生成するために多くのエンドポイントへリクエストをする必要があるかもしれない。比較して GraphQL では単一のエンドポイントへリクエストするのみ。

query {
  books {
    id
    title
    author
    isbn
    price
  }
}

データフェッチ前後の話

REST 仕様の各エンドポイントでデータフォーマットが固定されているため、GraphQL と比べて REST で必要なデータをさらにフェッチするという点においてはかなり直感的です。同様に REST ではデータセットのフェッチが簡単でクライアントが必要な情報をさらにリクエストすることが出来る。

その点、GraphQL ではかなり異なっている。クエリ言語であり宣言的なデータフェッチをサポートしているため、利用者は実際に必要なものだけをサーバから取得できる。

本のタイトルと値段だけセレクトする例

query {
 books {
   title
   price
 }
}

エラーハンドリング

REST 仕様の API でのエラーハンドリングは極めて簡単だ。すべきことは HTTP ヘッダのレスポンスを検査するだけ。ステータスコードに応じて、適切な解決方法と同様にすぐにエラー記述を書くことが出来る。一方で GraphQL の場合はどのケースでも 200 OK を常に受け取ることになる。

Request: query { books { error_field } }
Response:
Request Method:POST
Status Code: 200 OK
{“errors”:[{“message”:”Cannot query field \”error_field\” on type \”Book\”.”,”category”:”graphql”,”locations”:[{“line”:3,”column”:3}]}]}

キャッシング

REST はすでにキャッシュを有効にしている HTTP を使用して強制されるため、リソース取得を自然と避けることも可能。一方で、GraphQL 自身はキャッシュ機構を持っておらず利用者が自らキャッシングの機構を作成する必要がある。

では GraphQL の利点は?

バージョン管理

REST の場合、いわゆる /api/v1/, /api/v2/ のようにバージョン移行の期間が必要であったり、変更に対して柔軟に対応できるというわけではない。GraphQL は必要なデータだけをリバウンドさせるため、直近で加えられた機能をフィールドに組み込んで、レスポンスが以前の状態から改ざんされることによって生じる問題は出てこない。

サポート終了が容易

GraphQL を使用している間は、フィールドを都合よく廃止することが可能。GraphQL 利用者はクエリに必要なフィールドについて言及する必要がある。

‘author_name’ => [
  ‘type’ => Type::string(),
  ‘deprecationReason’ => ‘Deprecated. Use author field’,
],

REST API では違ったお作法になる。ベースとなるエンドポイントはすべての REST API からアクセス可能であるが、それらがすべて疎結合なフィールドセットになるというわけではない。 比較して GraphQL は特定のフィールドの利用状況を監視することが非常に簡単になる。API 側からは引き出しているフィールドから特定のクライアントにアクセスすることが出来る。

フィールドの利用状況がわかりやすいというのがいまいちピンと来てない

ただし、あれだな、GraphQL の場合は同じ名前空間でやらないといけないので、String だったものを Object にしたかったら一旦別のフィールドを用意してそちらに移行し元のフィールドを直すという2ステップ必要になるから、まぁまぁ利点かどうかというと…

パフォーマンス最適化

REST ではデフォルトで完全なデータを要求するが、GraphQL の場合は最小限のリクエストで済ます。

では GraphQL の不利な点は?

キャッシングが簡単ではない

HTTP キャッシングとして当然のようにクライアントでも、サーバーでも現存の資産を利用できる REST と違い、GraphQL はまったく別のアプローチを取らなければならない。REST のようにそうそう簡単ではなく、データセットを再アレンジする必要があれば、Redis のキャッシュを利用する必要があったり、クライアント側のキャッシュがあることを祈る必要があったり…。

GraphQL 公式でも、エンドポイントベース API ではクライアントは HTTP キャッシングを利用するし、クライアントがキャッシュ構築のための手段として一意の識別子として API の URL が発行されるが、GraphQL では単一エンドポイントであるために識別子を持たない。クライアントが使用するためには識別子を公開するのがベストプラクティスである とのこと。

https://graphql.org/learn/caching/

認証の問題

GraphQL 自身はクエリ言語であり、認証自体の機構を持ちえない。データストアとクライアントに間に存在するレイヤーであり、認証は完全に独立したレイヤーである。言語自体がアプリケーションの認証をサポートするわけではない。ただし、GraphQL を利用して、クライアントとの間にエントリートークンを無理やり紐づける方法もあるにはある。REST が出来ることとは全く違うアプローチになる。

n + 1 問題

GraphQL の n + 1 問題 is 何

GraphQL で最適化しないとすると、1つのクエリに対して多数のラウンドトリップを送信することになる。適切なキャッシング、バッチ処理がないようなノープランなサーバでは、フィールドがリクエストされるたびにDBへのリクエストを発行することになる。Facebook 製の DataLoader などを利用することでバックエンドのパフォーマンスを向上することが可能。

DataLoader is 何

DataLoader はユーザーがデータを読み込んで GraphQL 関数にアクセスできるようにするためのユーティリティ。これを使って、SQL クエリに頼るのではなく、レコードから直接データを読み取ることが可能。

どう動いているか

DataLoader は、基本的にバッチ処理とキャッシュ処理の両方を使用します。これは、クライアントからリクエストされた複数のクエリ/リクエストに対するレスポンスをバッチロードするために使用できる。また、レスポンスをキャッシュして、同様のリソースに関する連続した問い合わせにアクセスできるようにする。

GraphQL の Queries, Mutations, そして Subscriptions

Queries

クライアントからサーバーへのデータリクエスト。複数のエンドポイントで実現し、データフォーマットがある REST とは異なり、GraphQL は単一のエンドポイントしか開示しておらず、クライアントはあらかじめ定義されたフレームワークから実際に必要な情報を判断できる。

例:

{
 Users {
   name
 }
}

上記のクエリのフィールド "Users" はルートフィールドと呼ばれ、それ以降のデータはペイロードと呼ばれる。 このクエリは、すべてのユーザーの名前のリストとなる。

{
  "Users": [
    {"name": "Damira"},
    {"name": "Michael"}
    {"name": "Salman"}
    {"name": "Sara"}
    {"name": "Maria"}
  ]
}

このクエリによってユーザー名が生成されたことは注目に値する(これは、クエリでは名前のリストのみが必要であることを明確に示しているため)。追加のリクエストについては、具体的な詳細を追加する必要がある。

たとえば、リストから最後の3人のユーザーの情報にアクセスしたいとすればどうするか。

{
  Users (last: 3) {
    name
    username
  }
}

いわゆる CRUD の create, update, delete あたりは次の Mutations。

Mutations

データの作成、更新、または削除に使用されう。最初の部分に "Mutations" という言葉を含める必要があるという点を除いて、構造はほぼ同じ。

mutation {
  createUser (name : "John", username: "jo123"){
    name
    username
  }
}

Subscriptions

サーバーへのリアルタイムリンクを設定し、保持することが可能。これにより、関連するイベントに関するリアルタイムの情報を得ることができる。ほとんどの場合、クライアントは対応するデータを取得するために特定のイベントに登録する必要。

正直 Subscriptions については理解していない。 プッシュ通知とか。データストアの Mutations 監視して何か出来るの?

Pros, Cons を理解する

GraphQL に利点はあるが、欠陥や欠点も多い。バリデーション、ポリシー、キャッシング。枚挙に暇がない。 フルFWでもないので利用者に対してこれらのレイヤーをどうするかの解決策は提示していない。 バックエンドサーバとクライアントとの間で疎通認識がまだ固まっていない状態であると混乱を招く恐れがある。

REST API からの急な移行はできなくても段階的に試すことは可能である。

結論

RESTful API は実績がある。信頼度も高い。REST が出来なかったことが GraphQL は出来ることもある。お互いを埋めるような存在なのでは。 GraphQL と REST は RDB と NoSQL の状況ととても似ている。 GraphQL が解決できる問題が多いものの、どちらか一方の API 仕様を選択するのは難しい。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment