仕事で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メソッドが呼ばれ、メソッドの返却値がクリエの結果として返却される。
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!"が返却される。
確認用にちょっと改造
スキーマにもう1つfieldを追加して、動作確認してみる。
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
このコマンドを実行すると以下のファイルが生成される
module Types
class PostType < Types::BaseObject
field :title, String, null: true
field :rating, Integer, null: true
end
end
クエリで型を指定した時に値が返却されるようにスキーマを書き換える
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を追加
module Types
class PostType < Types::BaseObject
field :id, ID, null: false # 追加
field :title, String, null: true
field :rating, Integer, null: true
end
end
次はスキーマでもidを受け取れるように改造
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"
]
}
]
}