この記事の内容
Railsで開発の仕事をしています。**GraphQL is 何?**ぐらいのGraphQL
初心者だったのですが、とにかくにも業務で急ぎ実装しなければならなかったので、メモをとりながら作成することにしました。
この記事では、RailsアプリにGraphQL
を取り入れ、データをGETする下準備までを範疇に入れています。
続きはいかに徐々に記していく予定です。
- 初めてのGraphQL with Rails ②(Apollo Client編)
- 順次追加予定...
GRaphQLとは?グラフって何??
グラフ理論という理論があるそうです。この理論では、データの構造を点と点を線で繋ぐような形で理解します。この構造をGraphと呼びます。GraphQL
の最後のQL
はこのGraph
にQueryLanguage(問い合わせ言語)を足して、GraphQL
と呼んでいるのだと理解しています。
▼Graph理論そのものについてはこちら
なぜGraphQLを使うの??
これまでデータベースとクライアント側のやりとりとの方法として、RESTful API
と呼ばれる方法が一般的でした。このRESTful API
の欠点が、データの過剰取得にあったそうです。GraphQL
はこの弱点を克服し、その時必要なデータを必要なだけ持ってくることができます。
▼RESTful API
とは何か、その欠点とGraphQL
の特徴について
▼データの過剰取得とはどのようなことか
GraphQLのある場所
GraphQL
を理解する上で、GraphQL
がアプリの構造上どこにあるのかを理解するのは非常に大切でした。
結論から言うとデータベースとインターフェイスとの間で、サーバーとクライアントのリクエストの間に入って、色々調整してくれるようです。公式サイトのトップにあった、この図がわかりやすいのではないかと思います。
画像引用元:GraphQL公式サイト
データベースとディバイスとの間にGraphQL
が記載されていますね。
GraphQLでAPIを作るのに必要なもの
GraphQLでAPIを実装をするために必要なものは、以下の3つであると理解しています。
名前 | 役割 |
---|---|
クエリ言語 | GraphQLサーバーへの問い合わせ内容を記載した言語 |
スキーマ言語 | GraphQLサーバーでのデータの型を記載した言語 |
リゾルバ | 問い合わせを実行するメソッド |
この辺は既存記事に非常に優れた記事があります。特に下記の記事が理解に役立ちましたので貼付をしておきます。
ここでは、GraphQL
が上記の**「問い合わせ」「データの型」「問い合わせの実行」**の3つのパートで成り立っていることの理解に留めておきます。
で、Railsでどうやるの??
上記の内容をRails
で表現する場合、graphql-rubyというGemが便利です。今回もそれを利用します。以下、graphql-ruby
の実装記事です。
本来のGraphQL
の記載方法を知りたい方は↑上記の記事や下記の公式チュートリアルなど取り組んでみると良いと思います。
本記事の参考記事
本記事で実装している内容については主にこちらの記事とgraphql-rubyの公式サイトを参考にしました。
今回表現した内容
今回は以下のようなusers
テーブルから**「ユーザー一覧」「ユーザー詳細」**をGETしてくるまでをGraphQL
で表現したいと思います。
users | |
---|---|
id | integer |
name | string |
string |
はじめに
まずはgraphql-ruby
を使えるようにします。
# Gemfile
gem 'graphql'
group :development do
gem 'graphiql-rails'
end
# ターミナル
$ bundle install
$ rails g graphql:install
上記のコマンドで大量のファイルが生成されます。生成されたファイル一覧です。
create app/graphql/types
create app/graphql/types/.keep
create app/graphql/portraits_uploader_schema.rb
create app/graphql/types/base_object.rb
create app/graphql/types/base_argument.rb
create app/graphql/types/base_field.rb
create app/graphql/types/base_enum.rb
create app/graphql/types/base_input_object.rb
create app/graphql/types/base_interface.rb
create app/graphql/types/base_scalar.rb
create app/graphql/types/base_union.rb
create app/graphql/types/query_type.rb
add_root_type query
create app/graphql/mutations
create app/graphql/mutations/.keep
create app/graphql/mutations/base_mutation.rb
create app/graphql/types/mutation_type.rb
add_root_type mutation
create app/controllers/graphql_controller.rb
route post "/graphql", to: "graphql#execute"
create app/graphql/types/node_type.rb
insert app/graphql/types/query_type.rb
create app/graphql/types/base_connection.rb
create app/graphql/types/base_edge.rb
insert app/graphql/types/base_object.rb
insert app/graphql/types/base_object.rb
insert app/graphql/types/base_union.rb
insert app/graphql/types/base_union.rb
insert app/graphql/types/base_interface.rb
insert app/graphql/types/base_interface.rb
insert app/graphql/アプリ名_schema.rb
生成されたファイルの中で、この2ファイルはgraphql-ruby
の構造を理解する上で特に重要だったと思います。
app/graphql/types/query_type.rb
app/graphql/アプリ名_schema.rb
全体のステップ
graphql-ruby公式サイトのチュートリアルによると、RailsでGraphQLによるサーバーへの問い合わせをするのに必要なステップは次の3つだそうです。
- 型を決める
- それらの型とスキーマをつなぐ
- クエリをスキーマで実行
一つ一つ見ていきます。
型を決める(型ファイルの作成)
RailsではコマンドでGraphQLの型ファイルが生成できます。
$ rails g graphql:object User
create app/graphql/types/user_type.rb
生成されたファイルの中身がこちら。
module Types
class UserType < Types::BaseObject
field :id, ID, null: false
field :name, String, null: false
field :email, String, null: false
field :created_at, GraphQL::Types::ISO8601DateTime, null: false
field :updated_at, GraphQL::Types::ISO8601DateTime, null: false
end
end
既にUser
モデルがある場合には、それに合わせて型を生成してくれるようです。初めは
$ rails g graphql:object User name:String email:String
のように書いていたのですが、既にUser
モデルがあったため、name
カラムとUser
カラムが2つずつできてしまいました。
スキーマファイル
上記で定義した内容を実行するためのファイルが必要です。
作成したスキーマファイルは下記の通りです。
module Type
class QueryType < GraphQL::Schema::Object
# フィールド(:user)の説明と引数を記載します。
field :user, Types::UserType, null: true do
description "Find User by ID" #省略可
argument :id, ID, required: true
end
# 実行のコマンド(リゾルバ)を書きます
def user(id:)
User.find(id)
end
def users(page: nil, items: nil)
User.all
end
end
end
初めは既存ソースをコピーしながらすることになると思いますが、ここでわからない単語やメソッドがたくさん出てきます。わからないことは地道に
などで調べます。
上記のコードを理解するにあたり、調べたのは下記の通りです。
field
クラスメソッド。データを(DBから)持ってくるするもの。objectとinterfaceがfieldを持っています。(object
とinterface
がそれぞれ何であるかは、名前の部分のリンク先を見てください。)
fieldは下記のような形で書きます。(他の書き方もあります。詳細はfieldのドキュメントを参照のこと)
field :name, String, null: true do
description "The name of this thing"
end
ブロックの1行目にはfield :フィールド名, 型の場所, nullになる可能性の有無 do
がそれぞれ書かれています。
注意しないといけないのは、フィールドと同名のメソッド(リゾルバ)を定義した場合、実際に帰ってくるのはリゾルバの値だということ。
例えば先ほどのコードを少し書き換えて
field :user, Types::UserType, null: true do
argument :id, ID, required: true
end
def user(id:)
# User.find(id) ここを書き換え
User.where(name: "山田太郎")
end
にすると、返ってくるのは「山田太郎」さんのデータになります。
Arguments
検索やデータの呼び出しに使う引数です。例えば
field :user, Types::UserType, null: true do
argument :id, ID, required: true
end
↑このargument :id
の部分を定義することで、
{
user(id: 1) {
name
email
}
}
のようなid: 1
のユーザーを呼び出すクエリがクエリが書けるようになります。
その他、以下のような書き方も載っていましたので、
{
customers(first: 5) {
name
outstandingBalance
}
}
{
posts(startYear: 2018) {
id
}
}
Railsにおけるorder
やlimit
、検索のキーなどもここで定義できるようです。
pageやitemsなど
現段階では不明(すみません)。ただ、graphql-ruby
はpagenationに特別なページを割いているので、多分それ関係の設定なのではないかと理解。違ったら訂正します。&わかったら追記します。
▼近そうな実装の記事も貼っておきます
ルートとなる型
graphql-ruby公式サイトのチュートリアルには**「スキーマファイルを作る前にエントリーポイント(query root)を決めておいてね」**と書いてあります。
どういうことかというと、全てのスキーマにはrootとなる型があるようです。
どうやらGraphQLそのものに「ルート型」という概念があり、(GraphQL公式サイトには該当となる用語は見つけられなかったのですが、書籍『初めてのGraphQL』にはルート型という言葉で出てきていました)
それが、
$ rails g graphql:install
をした時に生成された、こちらのファイルに記されています。
app/graphql/アプリ名_schema.rb
このファイルにはこのように書かれており、
class AppNameSchema < GraphQL::Schema
# required
query Types::QueryType
# optional
mutation Types::MutationType
subscription Types::SubscriptionType
end
データの**「呼び出し(query)」「変更(mutation)」「サブスクリプション(subscription)」がそれぞれどこのスキーマで行われるか記載してあります。型の位置(Types::QueryType
など)はルートとなる型ファイルからの相対位置**で記載されていますので、そのために先に「エントリーポイント(ルートとなる位置)」を決めておいてねと言うことなのかと理解しています。
スキーマの実行
こちらは、graphql-rubyのクエリの実行に関する記載にも若干の記載はありますが、graphql-ruby
の外のライブラリを使用して行うのが一般的なようです。
graphql-ruby
のサイトでも
- Relay
- Apollo Client
- GraphQL.js Client
が例として挙げられています。
業務ではApollo Clientを利用しましたが、一旦、長文になりそうなので別記事に記載したいと思います。
ここまでの感想
調べ始めたらとても奥が深かったです。。。。
この記事も中途半端になってしまって恐縮ですが、理解したらとても便利そうなので、もう少し勉強を深めたいと思います。