GraphCMSで学ぶGraphQL 第1回 GraphQLとは

最近メジャーなサービスのAPIとしても採用されることが増えているGraphQLと、そんなGraphQLを使ったheadless CMSである、GraphCMSについて解説していきます。まずは概要を大きく捉えてみましょう。

発行

著者 宇野 陽太 フロントエンド・エンジニア
GraphCMSで学ぶGraphQL シリーズの記事一覧

はじめに

本シリーズでは、最近メジャーなサービスのAPIとしても採用されることが増えているGraphQLと、そんなGraphQLを使ったheadless CMSである、GraphCMSについて解説していきます。

第1回目の今回は、GraphQL・GraphCMSの概要と特徴を、それぞれ紹介していきます。

GraphQLとは

GraphQLとは、Web APIにおいて、そのインターフェースに利用されることを想定したクエリ言語と、そのクエリを実行するサーバーサイドのランタイムのことを指します。Facebookによって開発されたのち、オープンソース化され、現在はGraphQL Foundationによって管理されています。

GraphQLの採用事例

GraphQLは、開発元のFacebookをはじめとして、AirbnbやGitHubなど、海外の有名企業が採用しています。

一般的なWeb APIは、クエリストリングやリクエストボディに、キーバリューのペアやJSONなどを用いてリクエストを行います。GraphQLでは、これらのデータの代わりにGraphQLクエリをリクエストパラメータに渡すことで、リクエストを行います。

GraphQLの大きな特徴として、「クライアントが求めるデータを、データ構造を指定して問い合わせることができる」という点があります。それがどういうことなのか、次の節から解説していきます。

Web APIとGraphQLについて

Web API全般については、「Web API入門」を参照してください。このシリーズの最終回では、GraphQLの概要についても触れています。

データ構造を指定して問い合わせる

GraphQLの特徴について、実例を挙げて考えてみましょう。ここでは、CodeGridの著者紹介画面を、GraphQLを使って実装することを考えてみます。

この画面では、CodeGridの著者の情報が表示されています。著者の情報は、名前や肩書、アイコン画像と、執筆した記事一覧などで構成されています。

これらをまとめると、クライアントでの描画に使うデータは、次のような構造になっていると扱いやすそうです。実際のCodeGridの画面の「執筆した記事」データには、ほかにも、シリーズの情報やカテゴリ情報など含まれていますが、長くなってしまうのでここでは割愛します。

- 特定の著者
  - 名前
  - 所属
  - 肩書
  - アイコン画像(のURL)
  - 説明
  - 執筆した記事
    - タイトル
    - 第n回あるいは前編/後編
    - シリーズタイトル
    : (省略)

GraphQLの特徴は、このデータ構造をそのままクエリとしてリクエストすることができ、なおかつその構造のままデータが返ってくる、という点です。

上記のデータを取得するクエリは、次のようになります。

query {                             # データを取得するクエリですという宣言
  author(where: {slug: "cancer"}) { # 特定の著者の…
    name                            # 名前
    affiliation                     # 所属
    title                           # 肩書
    icon {                          # アイコン画像の…
      url                           # URL
    }
    description                     # 説明
    articles(first: 1000) {         # 執筆した記事(最大1000件)の…
      title                         # タイトル
      part                          # 第n回あるいは前編/後編
      series {                      # 属するシリーズの…
        title                       # タイトル
      }
      # 省略
    }
  }
}

ぱっと見ただけで、先ほどのデータ構造そのままになっていることがわかると思います。

このクエリを、GraphQLに対応したAPIにリクエストすると、次のようなデータが返ってきます。

{
  "data": {
    "author": {
      "name": "宇野 陽太",
      "affiliation": "PixelGrid Inc.",
      "title": "フロントエンド・エンジニア",
      "icon": {
        "url": "https://media.graphcms.com/hK4SZ5OrQUuoQsA86Guh"
      },
      "description": "大手ソフトウェアダウンロード販売会社、ソーシャルアプリケーションプロバイダーなどで、デザイナー、マークアップ・エンジニア、フロントエンド・エンジニアとして、主にスマートフォン向けゲームの開発に携わる。2015年1月に株式会社ピクセルグリッドに入社。\nMVCフレームワークを用いたJavaScriptの実装や、メンテナブルなCSSの設計を得意とする。",
      "articles": [
        {
          "title": "宇野 陽太編",
          "part": "第8回",
          "series": {
            "title": "エンジニアに聞く、仕事の行方"
          }
        }
        // 省略
     ]
    }
  }
}

トップレベルのキーが"data"になっているなど、細かな点に違いはありますが、リクエストしたクエリと同じ構造のデータが返ってきました。

この特徴は、「クライアントが何を求めていて、サーバーが何を返してくるのか」ということを把握するのに、大きな助けとなります。それにより、データのやり取りのために割くリソースを減らし、UIの開発作業により注力することができるようになります。

最小のデータを最低限のリクエストで取得する

次に、CodeGridの著者の一覧画面を見てみましょう。

著者紹介画面と同じように、この画面で欲しいデータ構造を考えてみます。

紹介画面と同様に、名前や肩書、執筆した記事の一覧が必要そうです。著者の説明はここでは表示しないので、これは不要でしょう。同様に、記事の詳細も必要なさそうですが、記事数を計算して表示する必要があるので、このためにIDだけ取得することにします*。また、著者をクリックしたら、その著者の詳細画面へ遷移するようにしたいので、著者を一意に特定できる値も必要ですね。

*注:IDとは

GraphCMSではすべてのデータに固有のIDが自動で振られます。ID自体は必要ないのですが、記事数の計算のために何らかのデータを取得する必要があるため、ここではIDを指定しています。

このように考えてみると、一覧画面のデータは、以下のような構造になっているとよさそうです。

- すべての著者
  - 名前
  - 所属
  - 肩書
  - アイコン画像(のURL)
  - 執筆した記事のID
  - 一意に特定できる値

先ほどの詳細画面で取得したデータと比べて、こちらのほうが必要なデータの量が少ないことがわかると思います。

ということは、詳細画面のデータを使い回してしまうと、無駄なデータをクライアントに送ることになってしまいそうです。一覧用と詳細用で別々のAPI、ないしはデータを用意する必要がある、ということでしょうか?

そんなことはありません。そもそも、GrpahQLは単一のエンドポイントしか持たず、どのデータを取得するか、というのは、クエリによって決まります。REST APIのように、エンドポイントによって返すデータが決まるということはありません。

また、複数のデータ構造を用途に応じて用意しておく必要もありません。実際、CodeGridでは、一覧のデータと詳細のデータは、どちらも同じものを使っています。

前述したように、GraphQLでは、クライアントが求めるデータ構造をそのまま返すことができます。逆を言えば、クライアントが必要としない(リクエストしていない)データを返すことはありません。

上記のデータを取得する場合のクエリは、以下のようになります。

query {                      # データを取得するクエリですという宣言
  authors {                  # すべての著者の…
    name                     # 名前
    affiliation              # 所属
    title                    # 肩書
    icon {                   # アイコン画像の…
      url                    # URL
    }
    articles(first: 1000) {  # 執筆した記事(を、最大1000件)
      id
    }
    slug                     # 一意に特定できる値
  }
}

このクエリでリクエストをすると、次のようなデータが返ってきます。

{
  "data": {
    "authors": [
      {
        "name": "中村 享介",
        "affiliation": "PixelGrid Inc.",
        "title": "Jamstackエンジニア",
        "icon": {
          "url": "https://media.graphcms.com/08EPcNB2QwqcPWdriqBq"
        },
        "articles": [
          {
            "id": "cjyjugko1494j08304cbjki3z"
          }
          // 中略
       ],
        "slug": "kyosuke"
      }
      // 中略
    ]
  }
}

このように、クエリにの構造を変更すれば、サーバーはその通りのデータを返します。

GraphQLでは、サーバー側では単一のデータ構造を再利用しつつ、クライアントに返すデータのサイズは削減する、といったことが可能になります*。

*注:REST APIでレスポンスを間引く

GraphQLの特徴として、クライアントが必要なデータのみレスポンスすることができる、という点を挙げましたが、この動作自体は、GraphQLでしかできないものではありません。

REST APIの場合でも、パラメータとして、レスポンスするフィールドを指定することができるようになっているAPIに出会ったこともあります。ただ、GraphQLと比べると扱いづらく、手間が多いというのが、筆者の感想です。

また、詳細画面でもそうでしたが、著者データと一緒に、執筆した記事のデータも返ってきています。これを見ると、著者のデータと記事のデータは分けるべきでは……と思う人もいるかもしれません。

CodeGridでは、著者のデータと記事のデータを、1つのデータとして扱っているのか? というと、それも違います。著者のデータと記事のデータは、サーバー上ではまったく別のデータとして登録されています。著者のデータの一部として記事のデータへの参照を持っているにすぎません。

このようなデータ構造を、きちんと設計されたREST APIで取得しようとすると、まずはじめに著者APIから著者のデータを取得した後、その中に含まれる記事IDを使って、記事APIにリクエストする……というように、複数のAPIにリクエストをしなければなりません。REST APIでは、データの種類ごとにエンドポイントを持つように設計します。

GraphQLでは、前述した1つのエンドポイントに対して、1つのクエリでリクエストしたデータは、参照さえ張られていれば、どれだけデータ構造が分かれていても、1回のレスポンスで返ってきます。このように、最小のデータを最低限のリクエストで取得可能であるという点も、GraphQLの特徴です。

ここまで述べた、GraphQLの特徴をまとめると、次のようになります。

  • クライアントが求めるデータを、データ構造を指定して問い合わせることができる
  • 最小のデータを最低限のリクエストで取得可能である

GraphCMSとは

このシリーズのもうひとつのテーマである、GraphCMSは、GraphQLの周辺ツールのうちの1つです。GraphCMSは、ドイツのGraphCMS社が開発・提供するheadless CMSです。データの取得や更新を行うためのAPIに、GraphQLを採用しています。CodeGridでもGraphCMSを採用しており、次のような画面になります。

GraphCMSはGraphQLを採用しているため、描画に必要なデータを柔軟かつ効率的に取得できるのが、大きな特徴です。CodeGridでも、リニューアルに際して、記事や著者などのデータをGraphCMSへと移行しました。メディアサイトくらいの規模であれば、相互に参照する必要のあるデータも多く、GraphQLの恩恵を得られる場面は多いのではと感じています。

GraphQL以外にも、データ型に合わせて選べるGUIや、Publish/Draftなどのステージの概念なども提供されており、実案件でのCMSとしても十分な機能を持っています。

とはいえ、GraphCMS以外のheadless CMSはGraphQLを扱えないかというと、そういうわけではありません。GraphCMSとの比較対象として挙がることが多いcontentfulもGraphQLを扱えますし、機能的にも大きな差はありません。

ただ、公式サイトのトップページにも「GraphQL native Headless CMS」とあるように、GraphCMSはGraphQLを中心に作られたheadless CMSです。ですので、ここではGraphQLを扱う際のheadless CMSの候補としてGraphCMSを取り上げていきます。

また、CodeGridでheadless CMSを選定した時点では、contentfulでは有料の上位プランでないとGraphQLが使えなかったため、GraphCMSを選んだという経緯もあります。現在はcontentfulでも無料プランで利用できます。

GraphCMSに関しては、次回以降、詳しく解説していきます。

GraphQLのそのほかの周辺ツール

GraphQL以外にも、GraphQLはその開発をサポートするツールやライブラリが充実しています。

たとえば、GraphQLを使ったリクエストを、Reactコンポーネントから実行しやすくするものとして、Apollo ClientRelayなどがあります。Apollo Clientには、React向けのライブラリのほか、AngularやVue向けのライブラリも公開されています。

graphql-tageslint-plugin-graphqlなど、クエリを静的解析にかけ、構文のチェックをしてくれるものもあります。これらを使えば、実際にリクエストを行わずとも、構文レベルでの間違いなどに気づくことができます。

クライアントから送られたクエリを受け取って実行する、GraphQLサーバーには、本家GraphQLプロジェクトが開発しているGraphQL.jsや、そのほかにApollo Serverなども有名です。また、JavaScript(Node.js)以外にも、数多くの言語の実行環境が作られています。

周辺ツールの中で規模の大きいものとしては、GraphiQLが挙げられます。これは、ブラウザ上でGraphQLクエリの実行環境を動かすというものです。GraphQLサーバーとあわせて、GraohiQLをホスティングしておけば、プログラムを一切書かずにクエリを実行することができます。

まとめ

今回は、GraphQLの特徴と、GraphCMSの概要について取り上げました。

GraphQLを使用することで、データを柔軟に取得することができるようになり、開発リソースをUIの開発に集中させることができます。また、効率的にデータを取得するので、パフォーマンス面でも優れています。ここではCodeGridを例に取り上げて解説しましたが、このようにUIを構築するためのデータが多岐にわたる場合、GraphQLは開発を強力に支援してくれます。

その一方で、データの種類もデータ量も少ないような場面では、これらの恩恵が得られず、オーバーヘッドのほうが目立ってしまう場合もあります。次回以降、どのようなデータをどのように扱っていくかを、具体的な例を通して解説します。

次回はGraphCMSについて解説していきます。