ITと筋トレの二刀流

未だゼロ刀流

GraphQLを5分だけプレゼンできるレベルで学ぶ

f:id:tatsuyashi:20190114232103p:plain:w300

GraphQL

最近ちらほら耳にするようになりました。

少しでも学んだことがある人は、

  • RESTの代わりになる?
  • Facebookが開発している

ぐらいは知っているかもしれません。

とはいえ、特にRESTで困ってないし、まだそこまで主流になっているわけでもないし、あまり深掘りしていない人が実際多いのかなと思います。

そこで今回はそういう人のために、一応名前は聞いたことがあるGraphQLというものについて、5分ぐらいは人に話せるレベルで浅ーーく説明します。

GraphQLって?

GraphQLはFacebook社が開発したAPI向けのクエリ言語です。

RESTとよく比較されますが、厳密にはRESTとは異なる存在です。
RESTはAPI 設計 のことを指しますが、GraphQLは1つの 言語 です。

比較されているのは、「GraphQLを用いたWebAPI」と「RESTful API」ですね。

クエリ言語?

クエリ言語って言われてもピンと来ない人がいるかもしれません。

私が似たようなものでイメージしたのは同じクエリ言語であるSQLです。

SQLがわからない人は、、、スミマセン)

例として、ユーザー情報をデータベースからSQLで取得する場合と、GraphQLを使ってAPIで取得する場合で比較します。

SELECT USER_ID, USER_NAME FROM USERS;

USER_ID USER_NAME
1 孫悟空
2 ベジータ

クエリを発行すると、欲しい結果がデータベースから返ってきます。

  • GraphQL
query {
  users {
    userId
    userName
  }
}

{
  "data": {
    "users" : [
      { "userId": "1", "userName": "孫悟空" },
      { "userId": "2", "userName": "ベジータ" }
    ]
  }
}

こちらもクエリを発行すると、欲しい結果がAPIのレスポンスとしてJSONで返ってきます。

どちらもクエリを発行して結果を得るのは同じですね。

GraphQLが生まれた背景

Facebook社がGraphQLを開発した背景にはFacebookならではの事情があります。

Facebookといえば全世界で利用されているSNSですね。

当然日本やアメリカのような国だけではなくて、全世界、それこそ通信状況の良くない国・地域からもアクセスされます。

通信状況が良くない場所からのアクセスを考えたときに、以下のような問題を解決する必要がありました。

  • 不必要な項目のリクエス
  • 様々なAPIを呼ぶことによる通信オーバーヘッド

これらの問題を解決するためにGraphQLが生まれました。

GraphQLの特徴

新しいものを学ぶときはその特徴を箇条書きで答えられるようになると、説明をしやすいですよね。

GraphQLの特徴としては、

  1. スキーマでの型指定とAPI定義

  2. 利用者が欲しい項目を選択可能

  3. 1度のリクエストで複数リソースを取得可能

の3点が挙げられます。

スキーマでの型指定とAPI定義

GraphQLではスキーマ上で型とAPIの定義を行います。

例として、ユーザーの一覧を返すAPIを考えます。

まず、ユーザを定義します。

type User {
  userId: ID!
  userName: String!
  age: Int!
  sex: String!
}

次に、APIを定義します。

type User {
  userId: ID!
  userName: String!
  age: Int!
  sex: String!
}

↓↓
type Query {
  getUsers: [User]
}

上記は「getUsersというAPIがUser型の配列を返す」ということを示します。

(type Queryについては後述します)

ここに、ユーザーIDを指定するとそのユーザ情報を返すAPIを追加してみます。

type User {
  userId: ID!
  userName: String!
  age: Int!
  sex: String!
}

type Query {
  getUsers: [User]
  getUser(userId: ID!): User   ←←
}

GraphQLではこのようにスキーマで型とAPIを定義します。

型指定しているので、getUsersとgetUser(userId: ID!)で返ってくるユーザー情報は同じ型であることが保証されます。

また、スキーマそのものがAPIのインターフェース仕様書にもなります。

利用者が欲しい項目を選択可能

GraphQLの大きな特徴として、「クエリ発行時に必要な項目を指定する」というものがあります。

先ほどのスキーマの内容でAPIが定義されているとします。

type User {
  userId: ID!
  userName: String!
  age: Int!
  sex: String!
}

type Query {
  getUsers: [User]
  getUser(userId: ID!): User
}

例えば、以下のようなデータ取得パターンがあるとします。

  • 全ユーザーの情報の一覧が欲しい
  • 全ユーザのIDの一覧が欲しい

GraphQLではどちらのケースもgetUsersのAPIで取得できます。

  • 全ユーザーの情報一覧
query {
  getUsers: {
    userId
    userName
    age
    sex
  }
}

{
  "data": {
    "getUsers": [
      { "userId": "1", "userName": "孫悟空", "age": "35", "sex": "MALE" },
      { "userId": "2", "userName": "ベジータ", "age": "38", "sex": "MALE" }
    ]
  }
}
  • 全ユーザーのID一覧
query {
  getUsers: {
    userId  ←userIdのみ指定する
  }
}

{
  "data": {
    "getUsers": [
      { "userId": "1" },  ←userIdのみ返ってくる
      { "userId": "2" }
    ]
  }
}

これにより、必要な項目に絞ってAPIを利用することができるようになります。

1度のリクエストで複数リソースを取得可能

例えば以下のようなユースケースがあるとします。 (例が無理矢理なのはご愛嬌)

指定したユーザーの情報と、全ユーザーの一覧を一画面で表示したい

先ほどの例にあったAPI(全ユーザー一覧取得APIと1ユーザー取得API)がGraphQLとRESTそれぞれで提供されていた場合で比較してみます。

RESTの場合

RESTの場合の選択肢は以下の2つが挙げられます。

  • 全ユーザー一覧APIと1ユーザー取得APIをそれぞれ呼び出す(2リクエスト)
  • 1ユーザー情報と全ユーザー一覧を取得するAPIを用意し、呼び出す(1リクエスト、API追加)

簡単に言うと、APIを2回呼ぶか、セットにした新規APIを作成するかの2択です。

GraphQLの場合

GraphQLの場合、以下のように1度のリクエストで複数のAPIを指定できます。

query {
  getUser(userId: "1") {  ←1ユーザー取得
    userId
    userName
    age
    sex
  }
  getUsers {  ←全ユーザー取得
    userId
    userName
  }
}

{
  "data": {
    "getUser": {
      "userId": "1",
      "userName": "孫悟空",
      "age": "35",
      "sex": "MALE"
    },
    "getUsers": [
      { "userId": "1", "userName": "孫悟空" },
      { "userId": "2", "userName": "ベジータ" }
    ]
  }
}

このように、GraphQLではAPIを組み合わせることで、利用者側の業務に合った情報を効率的に取得することができるようになります。

GraphQLのAPIの種類

GraphQLのAPIは以下の種類が存在します。

  • Query (データ取得)
  • Mutation (データ更新)
  • Subscription (変更検知)

これらはGraphQLスキーマでは予約語になっており、

type Query {
  getUsers: [User]
  getUser(userId: ID!)
}

type Mutation {
  createUser(userId: ID!, userName: String!, age: String!, sex: String!)
}

のようにそれぞれのAPIを定義します。

Subscriptionについて

Subscriptionは公式サイトでは言及されていません。(2019/1/14 現在)

GraphQL | A query language for your API

ただし、GraphQLのRFCではSubscriptionの仕組みについて言及されています。

graphql/Subscriptions.md at master · facebook/graphql · GitHub

概要としては、

  • 特定のMutationを監視する
  • 監視しているMutationが実行されると、実行した結果のオブジェクトが通知される

凄くざっくり図にすると以下のようなイメージになります。

f:id:tatsuyashi:20190115000612p:plain:w500

プログラミング言語のGraphQLのライブラリにおいては、Subscriptionの実装がなされているものが多いので既に利用できるようになっています。

RESTの代わりになりうる?

ここからは個人的な見解となりますが、

RESTの代わりはできるが、RESTを超えるほど広まらない と思っています。

何故かと言うと、逆にRESTがGraphQLの代わりをできる とも言えるからです。

GraphQLの特徴である、

はRESTでもできなくはないです。

  • スキーマによる型定義 → JSONスキーマを使う
  • 項目指定 → 項目を指定するパラメータをクエリに設定 (fieldsが一般的)
  • 1リクエストで複数API → 新規APIとして作成

もちろんGraphQLの方が便利ですし、上記のことが楽に行えるのは事実ですが、RESTでできることを多大な学習コストを払ってまでGraphQLでやるという選択をとることは少ないのかなと思います。(残念なことですが)

ただ、これからGraphQLをもっと簡単に導入できるような仕組みが増えていくと思いますし、GraphQL自体も進化して「GraphQLでしかできないこと」が出てくると形勢も変わってくるのかなと思います。
AWSのフルマネージドGraphQLサービスであるAWS AppSyncでは驚くほど簡単にGraphQLをセットアップできます)

GraphQLについて(まとめ)

今回はGraphQLの概要をメインで書きました。
「とりあえず新しいGraphQLというものを少し覚えたし、知らなそうな人にドヤするか!」ぐらいのことはできると思います。

スキーマの書き方などはもっと様々な手法がありますが、この記事以上に知りたい人はWebにたくさん情報がありますので是非調べてみてください。(人任せ)