LoginSignup
24
7

More than 1 year has passed since last update.

初めてのGraphQL with Rails

Last updated at Posted at 2021-09-08

この記事の内容

Railsで開発の仕事をしています。GraphQL is 何?ぐらいのGraphQL初心者だったのですが、とにかくにも業務で急ぎ実装しなければならなかったので、メモをとりながら作成することにしました。

この記事では、RailsアプリにGraphQLを取り入れ、データをGETする下準備までを範疇に入れています。
続きはいかに徐々に記していく予定です。

GRaphQLとは?グラフって何??

グラフ理論という理論があるそうです。この理論では、データの構造を点と点を線で繋ぐような形で理解します。この構造をGraphと呼びます。GraphQLの最後のQLはこのGraphQueryLanguage(問い合わせ言語)を足して、GraphQLと呼んでいるのだと理解しています。

▼Graph理論そのものについてはこちら

なぜGraphQLを使うの??

これまでデータベースとクライアント側のやりとりとの方法として、RESTful APIと呼ばれる方法が一般的でした。このRESTful APIの欠点が、データの過剰取得にあったそうです。GraphQLはこの弱点を克服し、その時必要なデータを必要なだけ持ってくることができます。

RESTful APIとは何か、その欠点とGraphQLの特徴について

データの過剰取得とはどのようなことか

GraphQLのある場所

GraphQLを理解する上で、GraphQLがアプリの構造上どこにあるのかを理解するのは非常に大切でした。

結論から言うとデータベースとインターフェイスとの間で、サーバーとクライアントのリクエストの間に入って、色々調整してくれるようです。公式サイトのトップにあった、この図がわかりやすいのではないかと思います。
Image from Gyazo
画像引用元: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
email 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

生成されたファイルの中身がこちら。

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つずつできてしまいました。

スキーマファイル

上記で定義した内容を実行するためのファイルが必要です。
作成したスキーマファイルは下記の通りです。

app/graphql/types/query_type.rb
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から)持ってくるするもの。objectinterfaceがfieldを持っています。(objectinterfaceがそれぞれ何であるかは、名前の部分のリンク先を見てください。)

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におけるorderlimit、検索のキーなどもここで定義できるようです。

pageやitemsなど

現段階では不明(すみません)。ただ、graphql-rubypagenationに特別なページを割いているので、多分それ関係の設定なのではないかと理解。違ったら訂正します。&わかったら追記します。

▼近そうな実装の記事も貼っておきます

ルートとなる型

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を利用しましたが、一旦、長文になりそうなので別記事に記載したいと思います。

ここまでの感想

調べ始めたらとても奥が深かったです。。。。
この記事も中途半端になってしまって恐縮ですが、理解したらとても便利そうなので、もう少し勉強を深めたいと思います。

24
7
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
24
7