僕とRailsとREST
初めてのWeb言語が Ruby on Railsで
Railsから多くのものを学んだ自分にとっては
Railsは 最強のフレームワーク
RailsはREST,CRUDをベースにしており
それこそが最先端!
一番イケていると思い込んでいました。
なのでRails
でGraphql
書くなんて、、、、
そんな、、、Rails
でも最も
大きなRail
のREST
から外れてしまうよ、、、
ありえない、、、って思っていたのですが、
いざ使ってみるとGraphql
最高!と感じたので
それについて書きます。
RESTなAPI
レシピサイトを作るとします。
エンドポイント(基本GET)が下記の表になるとすると
endpoint | 返す値 |
---|---|
/recipes |
レシピのURL一覧 |
/recipes/:id |
idで指定されたレシピ一つ |
/recipes/:id/foods |
idで指定されたレシピで使われる食材たち |
/foods |
食材URLたち |
/foods/:id |
idで指定された食材 |
/foods/:id/recipes |
idで指定された食材が使われているレシピを表示 |
こんなかんじ。
レシピの一覧から食材情報ほうを取ろうとする
1.まず recipes
でレシピのURL一覧を取得し
localhost/recipes
[
{"url":"recipes/1"},
{"url":"recipes/2"},
{"url":"recipes/3"}
]
2.そのあとに上のrecipe
のurlのid
をもとにrecipeの詳細を取得します。
localhost/recipes/1
{
"recipe": [
{
"recipe_id": 1,
"user_id": 2,
"title": "卵かけご飯",
"description": "ご飯の上に卵をかけ、そのあと醤油をかけます。",
"foods": [
{
"url": "/foods/1"
},
{
"url": "/foods/2"
},
{
"url": "/foods/3"
}
]
},
{
"recipe_id": 2,
"user_id": 3,
"title": "納豆ご飯",
"description": "ご飯の上納豆を載せます。。",
"foods": [
{
"url": "/foods/2"
},
{
"url": "/foods/4"
}
]
}
]
}
3.上のfood
のurlのid
をもとにfoodの詳細を取得します。
localhost/foods/1
{
"food_id":1,
"description":"卵",
"image":"egg.png"
}
URLが
resource
の場合は配列を返し、
resource
の場合は詳細情報を返すので
わかりやすいものの
food
まで情報を取ろうとすると
クライアントで何回もAPIにリクエストを送ることになります。
くずれたRESTなAPI
上のようにきっちり
REST
なAPIを実サービス書くことはないと思います。
僕が書く場合は
GET /recipes
(レシピの一覧の食材を表示したい場合)対して
{
"recipe": [
{
"recipe_id": 1,
"user_id": 2,
"title": "卵かけご飯",
"description": "ご飯の上に卵をかけ、そのあと醤油をかけます。",
"foods": [
{
"food_id": 1,
"title": "たまご"
},
{
"food_id": 2,
"title": "ごはん"
},
{
"food_id": 3,
"title": "醤油"
}
]
},
{
"recipe_id": 2,
"user_id": 3,
"title": "納豆ご飯",
"description": "ご飯の上納豆を載せます。",
"foods": [
{
"food_id": 2,
"title": "ごはん"
},
{
"food_id": 4,
"title": "納豆"
}
]
}
]
}
のようなレスポンスを返すように書くと思います。
ですが、listとは別に,画像のグリッドのページが作りたい
など
サービスによって様々な要求があり
URL
に?grid=true
のようなパラメータをつけて、コントローラーで制御したり、
新しいエンドポイント作り、処理はconcern
に逃して、共通化したり
REST
を崩しながら、APIを作って行くと思います。
Graphqlでは
エンドポイントは一つなので
例えばPOST
:localhost:3000/api/
とします。
query
を一つ定義してしまえば、対応することでができます。
ここではレシピ一覧のqueryのみ書きますが、
すでにfood
,recipe
はquery
に定義されているとします。
例えば上のレシピ一覧の場合
graphql-rubyを参考
以下のgraphqのクエリをlocalhost:3000/api/
に投げると
上のくずれたREST と同一の情報を取得することができます。
query
recieps {
edge{
node{
recipe_id
title
image
description
foods {
edges{
node{
food_id
title
}
}
}
}
}
}
edge
,node
はライブラリの仕様です、、、
ネストする場合必要です。
画像のグリッド表示にしたい場合は
foodにimage
を付け加えれば良いので
query
recieps {
edge{
node{
recipe_id
title
image
description
foods {
edges{
node{
food_id
title
image # ここ
}
}
}
}
}
}
食材をベースにしたレシピの一覧の場合は
レシピの画像と食材の画像を必要の両方必要とするなら
food
と recipe
の両方に
image
をつければよいのです。
###まとめ
graphqのクエリ
基本一つqueryを書いてしまえば
配列にすることも、ページネーションすることも容易です。
なのでコードもDRYにすることできます。
API側でqueryを実装してしまえば
クライアントが欲しい情報はクライアントで定義でき、
一つのリクエストで必要な情報を取得できます。
ドキュメントとエンドポイント
RESTで開発を進めて行くと
エンドポイントとドキュメントが膨大に増え
開発が苦しくなってきますが
Graphqlは一つのエンドポイントのみであり
定義されるスキーマにドキュメントが含まれているので
ドキュメントを省略することができます。