Rails+React構成にGraphQLをインストールする

2023/05/28に公開

データの準備

まずは、GraphQL で叩くためのデータが必要です。

データはデータベースなどから取得するため、まずはデータベースにテーブルを作っていきましょう。

下記コマンドでモデルを作成します。

Rails では、モデルを作成することで、同時にテーブルを作成・編集するためのマイグレーションファイルが生成します。

ここではまず、User モデルを作ることとします。

User モデルには、名前・年齢・メモの情報を持ったモデルとします。
コマンドの引数でカラム名:型を入れるとそれに合わせたマイグレーションファイルが生成できます。

$ docker-compose run --rm web rails g model User name:string age:integer memo:string

[+] Running 1/0
 ⠿ Container react_app-mysql-1  Running
      invoke  active_record
      create    db/migrate/20221219125045_create_users.rb
      create    app/models/user.rb
      invoke    test_unit
      create      test/models/user_test.rb
      create      test/fixtures/users.yml

上記の通り、モデルファイルとマイグレーションファイルが生成しました。

マイグレーションファイルは下記です。

class CreateUsers < ActiveRecord::Migration[7.0]
  def change
    create_table :users do |t|
      t.string :name
      t.integer :age
      t.string :memo

      t.timestamps
    end
  end
end

マイグレーションファイルが生成しているのでマイグレーションを実行しましょう。

$ docker-compose run --rm web rails db:migrate

[+] Running 1/0
 ⠿ Container react_app-mysql-1  Running
== 20221219125045 CreateUsers: migrating ======================================
-- create_table(:users)
   -> 0.0440s
== 20221219125045 CreateUsers: migrated (0.0451s) =============================

生成完了しました。

一応、データベースコンテナ入ってテーブルできているか確認します。

$ docker-compose exec mysql bash

bash-4.4# mysql -u root -p myapp_development
Enter password:
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 15
Server version: 8.0.31 MySQL Community Server - GPL

Copyright (c) 2000, 2022, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> desc users;
+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| id         | bigint       | NO   | PRI | NULL    | auto_increment |
| name       | varchar(255) | YES  |     | NULL    |                |
| age        | int          | YES  |     | NULL    |                |
| memo       | varchar(255) | YES  |     | NULL    |                |
| created_at | datetime(6)  | NO   |     | NULL    |                |
| updated_at | datetime(6)  | NO   |     | NULL    |                |
+------------+--------------+------+-----+---------+----------------+
6 rows in set (0.03 sec)

mysql>

これで GraphQL を扱うためのデータ箱は準備できました。

一応、データを仮で作っておきましょう。

rails のコンソール画面から直接データを入れましょう。

$ docker-compose exec web bash
root@198460a29b69:/myapp# rails c
Loading development environment (Rails 7.0.4)
irb(main):001:0> User.create
  TRANSACTION (1.0ms)  BEGIN
  User Create (12.9ms)  INSERT INTO `users` (`name`, `age`, `memo`, `created_at`, `updated_at`) VALUES (NULL, NULL, NULL, '2022-12-24 08:29:25.928998', '2022-12-24 08:29:25.928998')
  TRANSACTION (6.1ms)  COMMIT
=>
#<User:0x000000401ad6d760
 id: 1,
 name: nil,
 age: nil,
 memo: nil,
 created_at: Sat, 24 Dec 2022 08:29:25.928998000 UTC +00:00,
 updated_at: Sat, 24 Dec 2022 08:29:25.928998000 UTC +00:00>
irb(main):002:0> User.all
  User Load (3.0ms)  SELECT `users`.* FROM `users`
=>
[#<User:0x000000401aba4b18
  id: 1,
  name: nil,
  age: nil,
  memo: nil,
  created_at: Sat, 24 Dec 2022 08:29:25.928998000 UTC +00:00,
  updated_at: Sat, 24 Dec 2022 08:29:25.928998000 UTC +00:00>]
irb(main):003:0>

とりあえずは仮データなので、基本 Null 許容としていたので create で作成可能です。

GraphQL 導入

Rails で GraphQL を扱うためには、ライブラリをインストールしましょう。

gem ファイルに下記を追加します。

gem "graphql"

その後、Gemfile が更新されたのでインストールしましょう。

$ docker-compose run --rm web bundle install

Installing sprockets 4.1.1
Installing graphql 2.0.15
Fetching sprockets-rails 3.4.2
Installing sprockets-rails 3.4.2
Fetching graphiql-rails 1.8.0
Installing graphiql-rails 1.8.0
Bundle complete! 15 Gemfile dependencies, 73 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.

gem でインストールできたら、下記コマンドを実行し、環境準備します。

こちらについては、公式にも記載されている通りに進めて行きます。

https://graphql-ruby.org/

$ docker-compose run --rm web rails g graphql:install

[+] Running 1/0
 ⠿ Container react_app-mysql-1  Running
      create  app/graphql/types
      create  app/graphql/types/.keep
      create  app/graphql/myapp_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"
       route  graphiql-rails
      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/myapp_schema.rb

結構なファイルが生成しました。

実装方法

GraphQL はスキーマをベースにして実装されていきます。

まずは先ほど作成した User 関係のスキーマを作って行きましょう。

下記コマンドでスキーマを生成します。

$ docker-compose run --rm web rails g graphql:object User

[+] Running 1/0
 ⠿ Container react_app-mysql-1
      create  app/graphql/types/user_type.rb

スキーマの型については、下記の種類を用意しているようです。

https://graphql.org/learn/schema/#scalar-types

app/graphql/types/ディレクトリの中に type.rb として User のスキーマが作成されました。

# frozen_string_literal: true

module Types
  class UserType < Types::BaseObject
    field :id, ID, null: false
    field :name, String
    field :age, Integer
    field :memo, String
    field :created_at, GraphQL::Types::ISO8601DateTime, null: false
    field :updated_at, GraphQL::Types::ISO8601DateTime, null: false
  end
end

ここからスキーマを細かく定義していきます。

# frozen_string_literal: true

module Types
  class UserType < Types::BaseObject
    field :id, ID, null: false
    field :name, String, null: false, description: "名前"
    field :age, Integer, null: false, description: "年齢"
    field :memo, String, null: true, description: "コメント"
    field :created_at, GraphQL::Types::ISO8601DateTime, null: false
    field :updated_at, GraphQL::Types::ISO8601DateTime, null: false
  end
end

user のスキーマを修正しました。

そして Rails では、web/app/graphql/types/query_type.rbがルートスキーマの位置付けになるため、ここに先ほど作成したスキーマを定義します。

module Types
  class QueryType < Types::BaseObject
    # Add `node(id: ID!) and `nodes(ids: [ID!]!)`
    include GraphQL::Types::Relay::HasNodeField
    include GraphQL::Types::Relay::HasNodesField

    # 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 :user, UserType, "Find a user by ID" do
      argument :id, ID
    end

    def test_field
      "Hello World!"
    end

    # Then provide an implementation:
    def user(id:)
      User.find(id)
    end
  end
end

Graphiql のインストール

実際の GraphQL のクエリを確認するための Playground 環境を準備します。

下記のような画面で実際に作成したクエリを確認することが可能となります。

graphiql-sample

Graphiql に関しては、Rails 側で表示するのではなく、React で表示したいので React でインストールします。

React でのインストールについては、下記 Readme に記載している通りに実行していきます。

https://github.com/graphql/graphiql/tree/main/packages/graphiql#readme

まずは、React 側で Graphql と Graphiql を触るので、下記コマンドでインストールします。

$ docker-compose run --rm web yarn add graphiql graphql @graphiql/toolkit

インストール後は、Graphiql を実行するための、コンポーネントを用意します。

import { createGraphiQLFetcher } from "@graphiql/toolkit";
import { GraphiQL } from "graphiql";
import "graphiql/graphiql.css";
import React from "react";

export default function Graphiql() {
  const fetcher = createGraphiQLFetcher({
    url: "http://localhost:3000/graphql",
  });
  return (
    <div style={{ height: "100vh" }}>
      <GraphiQL fetcher={fetcher} />
    </div>
  );
}

Graphql のエンドポイントは、Rails の routes.rb に記載した通り、 POST メソッドの/graphqlです。

ですので、createGraphiQLFetcherの URL にはそのエンドポイントを渡します。

React では、react-routerなどを使って、http://localhost:3000/graphiqlでアクセスできるようにしておきましょう。

そうすることで、Playground が利用できるようになります。

念の為、rails 側の routes.rb は下記のようになっていることを確認してください。

Rails.application.routes.draw do
  # if Rails.env.development?
  #   mount GraphiQL::Rails::Engine, at: "/graphiql", graphql_path: "/graphql"
  # end
  post "/graphql", to: "graphql#execute"
  root 'home#index'

  get '*path', to: 'home#index'
end

ちなみに下記はコメントアウトしています。

if Rails.env.development?
  mount GraphiQL::Rails::Engine, at: "/graphiql", graphql_path: "/graphql"
end

が記載されていると、Rails 側の URL で、http://localhost:3000/graphiqlを表示してしまうので、コメントアウトなりで削除しましょう。

実際に Call してみる

実際に Call してみました。

graphiql-call

このようにして実際に User 情報が取得できるようになりました。

複雑なQueryの実装について実装について

まとめ

graphql は REST と比べると柔軟な開発が可能ですので、よかったら触ってみてください。

GitHubで編集を提案

Discussion