graphql-rubyのメモ（queryのみ）

仕事でgraphqlを使うことになったので、自分なりに勉強したメモを公開します。
この記事ではgraphql-rubyというgemを使い、自分で定義した型のデータをデータ取得用のリクエストを発行して取得するところまでの超基本のところまでのメモとなります。
Hello Worldに毛が生えた程度のものとなります。

# 前提
* ruby 2.5.1p57
* rails 5.1.6.1
* 上記の環境でrails newで動作確認用のrailsプロジェクトは作成済の状態
* ちなみにGraphQLについての知識はこの記事を書く前の時点でGraphQLという便利なインターフェースがあるらしい程度の知識


# セットアップ
## インストール
Gemfileに以下を追加し、bundle installする。

```
gem 'graphql'
```

## graphql関連の基本的なファイルを生成
```
rails g graphql:install
```

## その後、Gemfileに以下のgemが追加されるので、bundle installする
```
graphiql-rails
```


## この状態で動作確認してみる
http://localhost:3000//graphiql
にアクセスし、一番左のところに以下のクエリを入力し、実行ボタンを押す

```
{
  testField
}
```

以下のような結果が返ってきたら、成功。

```
{
  "data": {
    "testField": "Hello World!"
  }
}
```

# スキーマについて
上記のクエリに対して、以下のところで反応している模様。この部分をスキーマと呼ぶらしい。
ここでクエリの各項目(どうやらfieldと呼ぶらしい)が指定された時の動作を指定する。
例えば、下の自動生成したスキーマではクエリ内でtestFieldが指定されたら、test_fieldメソッドが呼ばれ、メソッドの返却値がクリエの結果として返却される。


```app/graphql/types/query_type.rb
module Types
  class QueryType < Types::BaseObject
    # Add root-level fields here.
    # They will be entry points for queries on your schema.

    # TODO: remove me
    field :test_field, String, null: false,
      description: "An example field added by the generator"

    def test_field
      "Hello World!"
    end
  end
end
```

クエリに指定されたfieldが何を返却するかを定義しているのが、query_type.rbということを理解。
今回はクエリにtest_fieldを含んでいるので、このクラス内のtest_fieldが実行され、"Hello World!"が返却される。


## 確認用にちょっと改造
スキーマにもう１つfieldを追加して、動作確認してみる。

```app/graphql/types/query_type.rb
module Types
  class QueryType < Types::BaseObject
    # Add root-level fields here.
    # They will be entry points for queries on your schema.

    # TODO: remove me
    field :test_field, String, null: false,
      description: "An example field added by the generator"

    field :test_field2, String, null: false,                  # 追加
      description: "An example field added by the generator"  # 追加

    def test_field
      "Hello World!"
    end

    def test_field2     # 追加
      "test2"
    end
  end
end
```

http://localhost:3000//graphiql
で以下のクエリを投げる。

```
{
  testField,
  testField2
}
```

期待どおり、testField2として"test2"が返却された。

```
{
  "data": {
    "testField": "Hello World!",
    "testField2": "test2"
  }
}
```




# graphqlのオブジェクトを生成
次はオブジェクトを定義してみる。
いわゆる型のようなものだと理解。

```
rails g graphql:object Post title:String rating:Int
```

このコマンドを実行すると以下のファイルが生成される

```app/graphql/types/post_type.rb
module Types
  class PostType < Types::BaseObject
    field :title, String, null: true
    field :rating, Integer, null: true
  end
end
```

クエリで型を指定した時に値が返却されるようにスキーマを書き換える

```app/graphql/types/query_type.rb
module Types
  class QueryType < Types::BaseObject
    # Add root-level fields here.
    # They will be entry points for queries on your schema.

    field :post, PostType, null: true do  # ここでPostTypeを指定
      description "Find a post by ID"
    end

    def post    # ここでpostが指定された時に返却する値を設定
      {
        "title" => "test_title",
        "rating" => 3,
      }
    end
  end
end
```

以下のクエリを投げる

```
{
  post {
    title
    rating
  }
}
```

投げると以下のような内容が返却される。

```
{
  "data": {
    "post": {
      "title": "test_title",
      "rating": 3
    }
  }
}
```

## 型にパラメータを指定できるようにする
idを指定してidに関連した値を取得する、というのはよくあるケースだと思うので、idを指定できるように改造。

まずはidを受け取れるように型にidを追加

```app/graphql/types/post_type.rb
module Types
  class PostType < Types::BaseObject
    field :id, ID, null: false        # 追加
    field :title, String, null: true
    field :rating, Integer, null: true
  end
end
```

次はスキーマでもidを受け取れるように改造

```app/graphql/types/query_type.rb
module Types
  class QueryType < Types::BaseObject
    # Add root-level fields here.
    # They will be entry points for queries on your schema.

    field :post, PostType, null: true do
      description "Find a post by ID"
      argument :id, ID, required: true      # 追加
    end

    def post(id:)     # idを引数で受け取れるようにする
      {
        "id" => id,                     # idをそのまま返却
        "title" => "test_title_#{id}",  # 動作確認用にIDをtitleに含める
        "rating" => 3,
      }
    end
  end
end
```

以下のようなスキーマを投げる

```
{
  post(id: 11) {
    id
    title
    rating
  }
}
```

すると以下の値が返却されてくる。

```
{
  "data": {
    "post": {
      "id": "11",
      "title": "test_title_11",
      "rating": 3
    }
  }
}
```

今回はスキーマ内でほぼ固定値のハッシュを返却しているが、実際にはここでidを元に何かを取得する処理を呼び出すような感じになるハズ。

## IDを指定しないクエリを投げると・・・
スキーマ内で'required: true'となっているので、バリデーションが行われてエラーとなるハズ。
確認してみる為に以下のクエリを投げる。

```
{
  post {
    id
    title
    rating
  }
}
```

返却値。やっぱり、エラーとなった。

```
{
  "errors": [
    {
      "message": "Field 'post' is missing required arguments: id",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "fields": [
        "query",
        "post"
      ]
    }
  ]
}
```


# 参考
http://graphql-ruby.org/

https://qiita.com/sukechannnn/items/b2168d7214992e5d37bf

https://qiita.com/193/items/bf9842af0e1df8fb7226