【邦訳】GraphCMSとContentfulの比較

## はじめに
　以下は、GraphQLのCMS、GraphCMSオフィシャルブログにおいて、Fabian Beliza氏が2017年12月13日に投稿した記事の邦訳です。

　Contentfulも、GraphCMSも、ヘッドレスCMSと呼ばれるサービスの一種であり、前者はREST APIによって情報に対してアクセスが行われるのに対して、後者ではGraphQLと呼ばれるクエリ言語を用いられています。元記事は、それぞれの長所・短所を具体例を交えながら解説したものです。

元記事: [GraphCMS vs. Contentful - API Perspective](https://graphcms.com/blog/graphcms-vs-contentful-api)

## 本文

　ContentfulはCMS市場において一大勢力と言える存在であり、しばらくはその傾向が続くでしょう。しかしながら、利用する上で生じる問題や煩わしいと感じる点がないとは言い切れません。例えば、SDK上の問題や、多くのエンジニアが次なる代替を望んでやまないRESTに付随したものがあげられます。

 この記事ではContentfulにおけるREST APIと、GraphQLの比較を行い、様々な視点からそれぞれが持つメリット・デメリットを明らかにしていきます。


#### The API
　GraphCMSとContentfulの大きな違いは、APIに関する技術にあります。GraphCMSでは、Facebookによって開発されたオープンソースなAPI向けクエリ言語であるGraphQLが利用されており、一方でContentfulでは分散処理における潮流として生まれたRESTが使われています。言うまでもなくRESTは、スタンダードな技術ですが、GraphQLもまた昨今注目を集め、多くの開発者たち注目するようになってきています。

 ともにAPIによってデータの取得および送信を可能にするという点においては似たような存在であり、広くフロントエンド領域において使われてきましたが、実際のところ非常に大きな違いを持っています。

　今回は、下記図のような例を使用していきます。
![DataModel.png](https://qiita-image-store.s3.amazonaws.com/0/223534/c7d32bd0-aeb3-a761-535c-cce3f33f9dbe.png)
*[こちら](https://graphiql.graphcms.com/simple/v1/footballexample)で、実際にAPIを操作してみることもできますよ。*

#### Querying

##### REST - Contentful
　REST APIによるクエリはその時々によってまちまちですが、もし普段から使っているのであればその肝を抑えてらっしゃるかと思います。まずは、Contentfulにおいて、4つの主要APIの1つである*Content Delivery API*についてみていきましょう。

 ちなみに、他には*Content Management*、*Content Preview*、そして*Images API*があります。それぞれ、エントリを表示する、コンテンツを作成・削除する、草稿を閲覧する、そして画像のやりとりを行うという異なる役割を果たします。

　*Content Delivery API*における典型的なGETリクエストは下記のようなものです。
![contentful_request.png](https://qiita-image-store.s3.amazonaws.com/0/223534/1d7b4628-5b03-051f-c23b-15eeb48564c9.png)

　"spaces"の後に続く文字列は私のテストスペースのIDを示しており、"entries"はそのスペースにおけるすべてのエントリを送信するという命令を持ちます。

![contentful_response_entries.png](https://qiita-image-store.s3.amazonaws.com/0/223534/3101aa8f-b31e-953a-1979-c14e46c94838.png)
　レスポンスは上記のようなものになります。ID、名前、およびメタデータといったエントリの大まかな情報を提供しています。

##### GraphQL - GraphCMS
　書き込みも読み込みも一つのエンドポイントで行うことができることは、GraphQLの大きな利点の一つです。CMSですべてのデータを取得するためのGraphQLクエリは下記のようなものです。
![simple_graphql_query1.png](https://qiita-image-store.s3.amazonaws.com/0/223534/5e131101-d2bb-0e33-9174-719779ce2dcb.png)

　すでに上述した、League、Division、Team、Player、そしてStadiumを含んだモデルについて、この例のようなクエリですべてを問い合わせることができます。一見、シンプルに一行で記述されたRESTによるGETリクエストと比べて複雑なもののようですね。しかしながら、ここで行われていることは単にAPIが返却するデータの構造を定義していることに他なりません。それはすなわち、誰かに尋ねるようなことをする必要なしに返却されるレスポンスがどのようなものか知ることができる、ということです。

　GraphCMSが提供するAPI Exprolerもまた差別化されたポイントであることを強調させてください。一度クエリを書き始めたら、どのようなデータが利用可能であるかといったヒントを簡単に得ることができますし、Ctrlキー + Spaceキーのショートカットによってオートコンプリートを利用することもできます。
![graphiql.png](https://qiita-image-store.s3.amazonaws.com/0/223534/8a332844-0c73-0143-cf3b-e9f027bb3cdd.png)

　以下のように、レスポンスはまさにリクエストにおいて定義した構造をもって返却されます。
![graphql_response1.png](https://qiita-image-store.s3.amazonaws.com/0/223534/0d83c533-ea46-bf6c-ec58-41edd536e5e2.png)

　例えばplayerの姓が必要ないなど、取得するデータを減らしたいならその項目をクエリから取り除けばレスポンスからも取り除かれます。もっと多くのデータが必要であるならば、必要なフィールドをクエリに付け足してください。これらは、ウェブクライアントやモバイルクライアントのようなマルチプラットフォームでデータ構造が異なるような時における、不要な労力を開発者から取り除いてくれることでしょう。

#### Adding content

##### REST
　Contentful APIでコンテンツを追加するためには、Content Management endpointを使います。エンドポイントは、***api.contentful.com/spaces/<SPACE_ID>/entries***ではなく***cdn.contentful.com.***になり、書き込みにはPOSTリクエストを用います。くわえて、追加されるべきデータをリクエストボディとして定義します。
![contentful_post.png](https://qiita-image-store.s3.amazonaws.com/0/223534/9f0f06e7-946a-bbbf-55eb-9eb2ab0bb675.png)

　成功した場合、新しく作成されたエントリの内容とシステムの持つフィールド、そしてメタデータがレスポンスとして返却されます。

 RESTの大きなデメリットの一つが、ネストされた、あるいは関連付けされたエントリを一つのクエリによって作成することができない点です。関連したエントリを一つ追加するたびに新しいクエリがまた一つ必要となり、さらにそれらを関連付けるためのクエリが別途必要です。

##### GraphQL
　GraphQLでは、エントリの問い合わせを行なった場合と同じように、シンプルな方法でエントリを追加することができます。先の例においては***query***というキーワードを用いていましたが、今回は***mutation***というキーワードを用います。**エンドポイントは先程と同じ**です。新しいteamを追加するmutationは下記のようなものです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/223534/2ee41504-a4f3-053e-0fbe-26131973939b.png)
　ここでは、二行目から四行目で作成したいデータとミューテーションを定義しています。さらにそのあとに続けて、このミューテーションに対するレスポンスのフォーマットを定義しています。

　もうお分かりかと思いますが、レスポンスは下記のような形式にて返却されます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/223534/73064b9a-64a4-10d5-482f-b258efda516c.png)

　ここまでご覧のように、GraphQLによるエントリの作成は単純明快で、しかも素早く行うことができます。入れ子構造のクエリは、より一層興味深いです。RESTでは複数のリクエストを行わなければ実現できなかった操作を、GraphQLのミューテーションでは1つのクエリによって済ませることができます。複雑なようですが、これから説明していきますのでまずは不安にならずに眺めてみてください。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/223534/94ac6074-538d-979f-c84e-e305108a017f.png)

　上記のように、チームを作成するミューテーションをいくつかのパラメータとともに送信してみます。最初の一つ（三行目）はチームが所属するdivisionのIDを示しています。次に、TeamのフィールドとしてteamNameを設定しました。さらに新たなstudiamを作成し、Teamに対して紐づけています。最後に、自動的にチームに関連付けされた新しいplayerを一人作成しました。
　たくさんのRESTリクエストを送信する代わりに、たった1つAPIを呼ぶだけですべてのことが完了してしましました。これらはすべてのモデルがすでにリレーションとして関連付けを行われているがために実現できたことです。

　同じことをREST APIによって実行しようとするならば、作成したいエントリそれぞれに対するリクエストを送信し、さらにそれとは別に適切な関連付けを作成するリクエストを行う必要があります。非常に大変な作業であるばかりではなく、コードのわかりづらさはどんどん増していくことでしょう。

　ちなみに、ContentfulはLinksと呼ばれた入れ子構造を持つクエリを提供しています。Linksを利用すれば、異なるモデルである2つのエントリを紐づけることができます。例えば、playerとteamを関連付けたければ、下記のようなボディを含むリクエストを送ることで実現可能です。

```
{
  "sys": {
    "type": "Entry",
    "id": "<playerId>"
  },
  "fields": {
    "teamName": {
      "en-US": {
        "sys": {
          "type": "Link",
          "linkType": "Entry",
          "id": "<teamId>"
        }
      }
    }
  }
}
```


#### Filtering
　クエリAPIの中でも、フィルタリングは欠かすことができないものです。いつもすべてのエントリ情報が必要とは限りません。例えば、一番最新のブログ投稿であったり、特定のチーム情報が必要であったりといった場合などがありますよね。

##### REST
　Contentfulではコンテンツタイプ、順序、テキスト検索を含んだ幅広いフィルターを提供しています。
　いま、1990年1月1日生まれ以降のbirthDateであるplayerの情報を要求するとしましょう。その場合、リクエストのURLは下記のようになります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/223534/455d556a-ad54-5e57-b5ff-738944c89f14.png)

そしてレスポンスは、
![image.png](https://qiita-image-store.s3.amazonaws.com/0/223534/ed89b1f6-daa6-04c9-7e39-46f7e5bc2476.png)
このようになります。

　このURLはとても非常にシンプルというほどではないですが、それでもわりあいシンプルですし、しっかりと要求した情報を返却してくれました。

##### GraphQL
　さて、GraphQLのもっとも楽しいところです。高い柔軟性を備えた問い合わせを行うことのできるGraphQLとフィルタリングを組み合わせることにより、情報を完璧にコントロールすることができるようになります。ただし、フィルタリングロジックはGraphQLにビルトインとして備わっているものではなく、サーバサイドで実装されている必要があるという点についてはご留意ください。それゆえに、GraphCMSにおけるフィルタリングは他のGraphQLサービスやサーバと異なることもあります。

　同様のフィルタによる問い合わせをGraphQLで表現すると下記のようになります。
![Graphcms_filter.png](https://qiita-image-store.s3.amazonaws.com/0/223534/8fca8cb4-eb30-8552-a2bb-8b39a53fdb4c.png)

　こちらについても、GraphCMSにおいてはAPI Explorerによるオートコンプリートによってどのようなフィルタが使えるか簡単に知ることができます。

　レスポンスはこれまで通り、リクエストで定義したような形式で返却されます。
![Graphcms_filter_response.png](https://qiita-image-store.s3.amazonaws.com/0/223534/96477e4c-3daf-6a0c-1e73-643149d19512.png)

#### Conclusion
　どちらのCMSも幅広いAPIツールを持ち、可能性を秘めています。

 ContentfulはREST APIの適切な維持によって機能を果たしますが、いつまでもRESTであることに変わりはありません。単純なリクエストを行うことすら段々と複雑になり、多くの、特にリレーショナルなデータを取り扱う時にはうんざりさせられることもあるでしょう。

 GraphQLはそのようなシーンこそ得意としています。開発者のエクスペリエンスはずっと改善されるでしょう。GraphQLは誰にでも理解されやすいコンセプトでありながら、非常に興味深いものです。ネストされた構造を持つデータの作成といったより複雑な操作についても理解・実装が容易いものとなるでしょう。

　結局のところ、どちらを選ぶかはその人次第です。複数のエンドポイントからリクエストを行い、データにアクセスするRESTがお好みなら、Contentfulを利用すると、もしかしたら、多分、幸せになれるかもしれませんね。もし、シンプルなクエリやセットアップを望み、そしてより先進的なエクスペリエンスを求めるのであれば、GraphQLは一見の価値ありです。ヘッドレスCMSが必要なら、GraphCMSとともに、私たちは喜んで力になります！

#### First True Multi-Platform Headless CMS
　Contentfulは多くのSDKを備えているものの、依然その利用は簡単なものではありませんし、技術的に世相を反映していないケースもあるかもしれません。

　GraphQLは真にマルチプラットフォームで動作する、初めてのテクノロジーです。フロントエンドアーキテクチャにおいてJSON通信を行なっているなら、是非使うべきものです。冷蔵庫でも、スマートウォッチでも、車やVRヘッドフォンでさえもより少ない労力によって必要とするフォーマットのデータを取得することが可能です。これでもまだ興味を持っていただけないなら、もうこれ以上何もできることはありません...

#### Final words
　もしこの記事によってGraphCMSに対する関心を持っていただけましたら、ぜひ気軽に私たちの[Slack Channel](https://slack.graphcms.com/)や[Twitter](https://twitter.com/graphcms)、もしくはOn-Site-Chatにてコンタクトしてくださいね。

 また、是非私たちの製品をご自身の目で見極めてください。GraphCMSのフリープランは、ご趣味の範囲やプロジェクトにおける試用の範囲であればいつまでも無料です。詳しくは[こちらの料金表](https://graphcms.com/pricing/)をご覧になってください。

 本文はここまでです。

### 補足
以下は、GraphCMS Enterprise ManagerであるAlexander Naydenov氏による補足です。


>Contentful has an alpha/beta GraphQL API now too – available in its enterprise plans, build over the REST API. It does not allow Write operations (GraphQL mutations).

 現在ではContentfulもalpha/betaバージョンのGraphQL APIを利用可能ですが、現状書き込み処理（GraphQLでいうところのmutations)はサポートされていないとのことです。

また、他にも有益な記事を紹介していただきましたので、ご紹介いたします。

+ [GraphQL Makes for the Best CMS](https://graphcms.com/concepts/graphql/)
+ [What Does "Headless CMS" Mean?](https://graphcms.com/concepts/headless-cms/)


 最後までお読みいただきありがとうございました。誤り等ございましたら、お手数おかけいたしますがご指摘頂けますと幸いです。
(本記事は、Alexander Naydenov氏より公開の許諾を頂いております)