これはRetty Inc. AdventCalendar2018 21日目の記事です。
昨日は @takumi-suzuki さんの リモート環境をFire HDに切り替えてみた でした。
FireHD が悲しい結末を迎えてしまいましたね。
はじめまして。Retty Web チームでインターンをしている宇野です。
インターンでは主に、オウンドメディアのRettyグルメニュース(以下、グルメニュース)の開発をしています。今回の記事では、グルメニュースに GraphQL を導入することにしたので、実際に触ってみたいと思います。
はじめに
最初に、GraphQL 導入の経緯を説明します。
グルメニュースには現在、記事を配信する側と入稿する側のサービスが別々に存在します。2つのサービスがあることにより、メンテナンスコストが倍になってしまい手間です。
そこで、API を作り一つのサービスにして、サーバーとフロントを分離しようとしています。この API 部分に GraphQL を利用します。
GraphQL とは?
Facebook が開発した、API のためのクエリ言語です。クライアントとサーバーのやりとりを簡単にするために使用されます。
例えば、User
情報を取得する場合 GraphQL では次のように書きます。
type User {
id: ID
name: String
}
type Query {
user: User
}
GraphQL はクエリ言語なので特定の DB やストレージに結びついておらず、RDB だけではなく localStorage
や REST API に対しても 使うことができます。
RESTful API との違いは?
RESTful API との違いを次の図で説明していきます。
RESTful は、ルーティングやスキーマの定義が自由なため、フロント側と並行して開発するのが難しいです。しかし、GraphQL だとエンドポイントは一つで、スキーマの定義もモデルの設計をしていれば問題なくできます。他にも、次のような pros/cons があります。
pros
- API 通信が1回で済む
- リソース毎に API と通信しない
- リソースの差分だけを指定して取得できる
- 既にページで持ってる情報を改めて取得しなくて良い
- JSONに似た構文で書きやすい
cons
- キャッシュが URL ベースでできない
- モニタリングが難しい
- エンドポイント毎の監視できない
GraphQL の導入
それでは、 GraphQL を使ってみましょう。グルメニュースは、PHP フレームワークの Laravel を使っています。
GraphQL のフレームワークにはlaravel のパッケージである Lighthouse を使用します。Lighthouse はディレクティブ(@
)を使って、モデルのリレーションやバリデーションを定義できます
Lighthouse のインストール
$ composer require nuwave/lighthouse
config ファイルの配置
php artisan vendor:publish --provider="Nuwave\Lighthouse\Providers\LighthouseServiceProvider" --tag=config
これで GraphQL を使い始めることはできますが、開発に便利なパッケージ laravel-graphql-playground
も一緒に入れましょう(以下、playground
)。playground
は、 ブラウザ で GraphQL のサーバにクエリを投げて結果を確認できるパッケージです。また、右側にあるタブ DOCS
や SCHEMA
で Lighthouse が生成したスキーマファイルを見ることができます。
composer require mll-lab/laravel-graphql-playground
Lighthouse ファイルの作成
ファイルは routes/graphql
以下に配置します。次の2つモデルを作成して、 playground でデータを取得してみます。
- shops テーブル
カラム名 | 型 |
---|---|
id | int |
name | string |
address | string |
- items テーブル
カラム名 | 型 |
---|---|
id | int |
name | string |
genre | string |
表を元にスキーマはこのようにしました。
type Shop {
id: ID!
name: String
address: String
items: Item @hasMany
}
type Item {
id: ID!
name: String
genre: Int
shop: Shop @belongsTo
}
type Query {
shops(
id: ID @eq
name: String @where(operator: "like")
address: String @where(operator: "like")
): [Shop] @paginate(model: "Shop")
items(id: ID @eq
name: String @where(operator: "like")
genre: Int @eq
): [Item] @paginate(model: "Item")
}
DOCS
と SCHEMA
タブの内容は次のようになります。(一部分のみ)
DOCS
SCHEMA
フロント側では、既にどちらも id
と name
は持っており、 address
と genre
が欲しいとします。
query {
shops(id: 2, count: 3, page: 1) {
data {
address
}
}
items(genre: 1, count: 3, page: 1) {
data {
id,
genre
}
}
}
{
"data": {
"shops": {
"data": [
{
"address": "92394 Armando Shores Suite 623\nDeckowshire, NV 22748"
}
]
},
"items": {
"data": [
{
"id": "4",
"genre": 1
},
{
"id": "6",
"genre": 1
}
]
}
}
}
shop
と item
の異なるリソースを一回の通信で取ってくることができ、 address
, genre
だけを取得することができました。
まとめ
GraphQL 導入の説明と Lighthouse を使って GraphQL に触ってみました。キャッシュやモニタリングなど難しい部分もあり、技術的に枯れていないので学習コストは高いかもですが、銀の弾丸はないんです。
まだまだ導入事例は少ない GraphQL ですが、とても便利なのでぜひ使ってみてください。
明日は @yongyu-li さんです。