12
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

DeNA IPプラットフォーム事業部Advent Calendar 2017

Day 24

Railsで育った僕がGraphQLに感動した話

Last updated at Posted at 2017-12-24

僕とRailsとREST

初めてのWeb言語が Ruby on Railsで
Railsから多くのものを学んだ自分にとっては

Railsは 最強のフレームワーク
RailsはREST,CRUDをベースにしており
それこそが最先端!
一番イケていると思い込んでいました。

なのでRailsGraphql書くなんて、、、、
そんな、、、Railsでも最も
大きなRailRESTから外れてしまうよ、、、
ありえない、、、って思っていたのですが、
いざ使ってみると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,recipequeryに定義されているとします。

例えば上のレシピ一覧の場合

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 # ここ
       }
     }
   } 
  }
 }
}

食材をベースにしたレシピの一覧の場合は

レシピの画像と食材の画像を必要の両方必要とするなら
foodrecipeの両方に
imageをつければよいのです。

###まとめ

graphqのクエリ

基本一つqueryを書いてしまえば
配列にすることも、ページネーションすることも容易です。

なのでコードもDRYにすることできます。

API側でqueryを実装してしまえば

クライアントが欲しい情報はクライアントで定義でき、
一つのリクエストで必要な情報を取得できます。

ドキュメントとエンドポイント

RESTで開発を進めて行くと
エンドポイントとドキュメントが膨大に増え
開発が苦しくなってきますが

Graphqlは一つのエンドポイントのみであり
定義されるスキーマにドキュメントが含まれているので
ドキュメントを省略することができます。

12
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?