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


## 僕と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](https://github.com/rmosolgo/graphql-ruby)を参考

以下のgraphqのクエリを`localhost:3000/api/`に投げると

[上のくずれたREST](https://qiita.com/m2mtu/private/1a2b589ee36e8efcafd6#%E3%81%8F%E3%81%9A%E3%82%8C%E3%81%9Frest) と同一の情報を取得することができます。

```
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は一つのエンドポイントのみであり
定義されるスキーマにドキュメントが含まれているので
ドキュメントを省略することができます。