Rails・GraphQL基礎 – イントロ & クエリ編

ここでは、Rails での GraphQL の基本的な使い方を整理していきます。

内容は、Udemy『Basics of GraphQL with Ruby on Rails』のセクション1「Introduction」とセクション2「Reading Data」を参考にしています。

詳細はそちらをご参照ください。

Introduction

GraphQL とは

GraphQLは、APIで使われるクエリ言語です。

2012年にFacebook社により作られ、2015年に公開されました。

1つのリクエストで横断的なデータを自由に取得することができるので、RESTful APIとの比較で、注目されているAPIの設計です。

GraphQL vs REST

GraphQL と REST の比較は次のとおりです。

GraphQLREST
利用方法HTTPHTTP
エンドポイント1つ複数
1リクエストで取得可能なリソース複数1つ
必要以上のデータ取得起こらない起こりやすい

GraphQLでは、APIのエンドポイントが1つで、必要なデータを必要な分だけ取得できます。

APIを利用する側としては、GraphQLの方がありがたいですね。

とはいえ、単純に「GraphQL もしくは RESTの方が良い!」というものではなく、それぞれに向き不向きがあるようです。

詳細はこちらを参照:REST vs. GraphQL: A Critical Review

この記事の著者(スゴ腕のAPI開発者)は、

「GraphQLは簡単で使いやすい。が、スケールには向かない、導入例が少ない、JSONでしかレスを返せない、古い設計への後戻り、etc.」

のように、 GraphQLの利用シーンは限定的 というスタンスです。

これを参考にすると、サクッと使いやすいAPIを作る時は、GraphQLで設計するのが向いています。

Railsでのセットアップ

RailsでGraphQLをセットアップする手順は次のとおりです。

まずはAPIモードでRailsプロジェクトを新規作成します。

$ rails new [project] --api --skip

Gemfileに graphql を追加します。

gem ‘graphql’
$ bundle install

そして、必要なファイルをインストールします。

$ rails g graphql:install

そうすると、app/graphql 配下に必要なファイルが生成されます。

テストツール GraphiQL

GraphQLには、「GraphiQL」というイケてるテストツールアプリがあります。

コマンドラインからもダウンロードできます。

Homebrewがあれば、必要なコマンドは次の1行です。

$ brew cask install graphiql

インストール後、Finderで「graphiql」を検索して、control 押しながらクリックすればOKです。

Reading Data

それでは、GraphQLを使ったHTTPによるデータの取得方法を具体的にみていきます。

「app/graphql/types」配下のファイルをいじっていきます。

リクエストとレスポンス

リクエストするエンドポイントは、前述のとおり1つで、「root_domain/graphql」のみです。

リクエストで送るGraphQLクエリは次のような感じです。

{
  field(arg: "value") {
    subField
  }
}

レスポンスは、指定した field のみがJSONで返ってきます。

query_type.rb

「types/quey_type.rb」は、普通のRailsアプリでいう「routes.rb」のようなもので、HTTPリクエストで問い合わせられる「field」を定義していきます。

デフォルトでは次のように書かれています。


class Types::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

試しに、QrahpiQLを使って、test_field を取得してみます。

test_field

ちゃんと指定したデータがJSONで返ってきました。

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

1つ注意すべき点は、Railsではスネークケースになってたフィールド名が、リクエスト・レスポンスでは、キャメルケースになっている点です。

ただし、これも filed の定義に「camelize: false」オプションを渡せば、全てスネークケースで利用できるようになります。

例えば次のような感じです。


class Types::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", camelize: false
  def test_field
    "Hello World!"
  end
end

camelize

filed の書き方

基本構造

先ほどみた例を、もう一度みてみましょう。


  # TODO: remove me
  field :test_field, String, null: false,
    description: "An example field added by the generator"
  def test_field
    "Hello World!"
  end

field の第1引数は「フィールド名」、第2引数は「レスポンスのデータ型」、第3引数は「null: true/false」となっています。

第3引数「null: true/false」で、返り値が null でもよいかどうかを指定します。これは必須項目なので、全ての field で定義する必要があります。

レスポンスのデータ型

レスポンスのデータ型は次の5種類 です。

  • Int:
    • A signed 32‐bit integer.
  • Float:
    • A signed double-precision floating-point value.
  • String:
    • A UTF‐8 character sequence.
  • Boolean:
    • true or false.
  • ID:
    • The ID scalar type represents a unique identifier, often used to refetch an object or as the key for a cache. The ID type is serialized in the same way as a String; however, defining it as an ID signifies that it is not intended to be human‐readable.

IDというのが少し特殊ですが、その名の通り、DBのIDに使われます。

クエリ引数

特定のIDのデータだけ取得したい場合などは、field に引数を指定する必要があります。

その場合は、field 定義に argument を追加します。


  field :test_field, String, null: false,
        description: "An example field added by the generator", camelize: false do
    argument :name, String, required: true
  end

  def test_field(name:)
    "Hello #{name}!"
  end

argument

ActiveRecord

Author というモデルを作り、そのデータをクエリで取得してみましょう。

まずモデルの生成です。

$ rails g model Author first_name:string last_name:string yob:integer is_alive:boolean
$ rails db:migrate

そして、適当にAuthorデータを作ります。

$ rails c
> Author.create first_name: "Keisuke", last_name: "Inaba", yob: 1988, is_alive: true
> Author.create first_name: "Stephen", last_name: "Hawking", yob: 1942, is_alive: false 
.
.
.

それでは実際にデータを取得するクエリを書いていきます。

返り値をネストさせたい場合は、types配下に別ファイルを作って field を定義していきます。

今回であれば、Author の field なので「types/author_type.rb」に書いていきます。

コード例は次のとおりです。


# app/graphql/types/author_type.rb
class Types::AuthorType < Types::BaseObject
  description "An author"

  field :id, ID, null: false
  field :first_name, String, null: true, camelize: false
  field :last_name, String, null: true, camelize: false
  field :yob, Int, null: false
  field :is_alive, Boolean, null: true, camelize: false
end

新しく type.rb ファイルを作成するときは、「Types::BaseObject」を継承させます。

そして、この「AuthorType」を取ってくる field を「query_type.rb」に書きます。

特定の author と、全ての authors を取得する field を定義してみます。


# app/graphql/types/query_type.rb
class Types::QueryType < Types::BaseObject

  field :author, Types::AuthorType,
        null:        true,
        description: "One author" do
    argument :id, ID, required: true
  end

  def author(id:)
    Author.where(id: id).first
  end

  field :authors, [Types::AuthorType], null: false

  def authors
    Author.all
  end
end

返り値が配列になる場合は、

[Types::AuthorType]

[Int]

のように記載します。

それでは、GraphiQLからリクエストしてみましょう。

GraphiQL

ちゃんとレスポンスが取れました。

このように1つのエンドポイントで、データを取ってくることができるんですね。

カスタムフィールド

type.rb ファイルにカスタムフィールドを追加することもできます。

Author の first_name と last_name を合わせた「full_name」フィールドを作ってみましょう。

先ほどの author_type.rb を次のように修正します。


class Types::AuthorType < Types::BaseObject
  description "An author"

  field :id, ID, null: false
  field :first_name, String, null: true, camelize: false
  field :last_name, String, null: true, camelize: false
  field :yob, Int, null: false
  field :is_alive, Boolean, null: true, camelize: false
  field :full_name, String, null: true, camelize: false

  def full_name
    ([object.first_name, object.last_name].compact).join" "
  end

渡ってくるオブジェクトは「object」でアクセスできます。

実際にGraphiQLでテストしてみましょう。

full_name

ちゃんといけてますね。

兵庫県西宮市生まれのフリーランスRailsエンジニア。案件によってWordPressの作業も請け負ったりしてます。2014年から2016年にかけてオーストラリアで生活。 現在は東京を拠点に活動。/ 前職・資格:公認会計士 / プログラミング言語:Ruby, JavaScript, HTML, CSS / 日本語・英語
コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です