LoginSignup
1
2

More than 1 year has passed since last update.

Docker Rails7 apiモード mysqlでGraphqlを使用する方法

Last updated at Posted at 2023-01-05

記事の内容

Graphqlをキャッチアップするにあたって、そもそもなんでGraphqlを使用するのか? からはじめました。
また、学習するにあたって初めて聞くような単語がたくさんあったので、メモがてらこの記事にまとめていこうと思いました。
この記事ではDockerでの環境構築からuserのindex,show,createまでを記載しようと思います。

Graphqlとは?

さっそくですが参考がとてもわかりやすかったのです。GraphQLを導入した有名なサービスも紹介されており面白いです。
API用のクエリ言語であり、REST APIではサーバ側で返すデータ構造等を決めていたが、実際にデータを使用するクライアント側で自由にデータを取得できます。
今日のスマホやSPAでは複雑なデータを扱うことが多いため、注目されている。

メリット・デメリット

メリット

  • フロント側でレスポンスの形式を指定できる
    • 必要なデータのみ取得でき、オーバーフェッチ、アンダーフェッチがなくなる
    • Swagger等の仕様書が必要なくなる
  • 型があるため堅牢
  • 一度に複数のリソースを取得できる
    • RESTでいう post/1,post/2のようなリソースを一気に取得できる

デメリット

  • 学習コストがかかる
  • キャッシュが REST よりも複雑になる。N+1問題等に気をつける必要あり。

単語

  • クエリ言語:Graphqlサーバへの問い合わせ内容を記載した言語
  • スキーマ言語: Graphqlサーバでのデータの型を記載した言語
  • リゾルバ: 問い合わせを実行するメソッド
  • Query: SQLでいうSELECTにあたるもの。データを取得する際に使用
  • Mutation: SQLでいうINSERT, UPDATE,DELETE。データを作成、変更削除する際に使用
  • field: クラスメソッド。データをDBからもってくる単位
  • Argument: 検索やデータの呼び出しに使う引数。Queryに渡す引数を指定。

実装

環境構築

1.各種ファイルを用意

以下ファイルを作成

Dockerfile
FROM ruby:3.1.2


RUN mkdir /app
WORKDIR /app
COPY Gemfile /app/Gemfile
COPY Gemfile.lock /app/Gemfile.lock
RUN bundle install
COPY . /app

# Add a script to be executed every time the container starts.
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000
EXPOSE 3306

# Start the main process.
CMD ["rails", "server", "-b", "0.0.0.0"]
docker-compose.yml
version: '3'
services:
  db:
    platform: linux/x86_64  #M1対応
    image: mysql:5.7
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: root
      MYSQL_USER: root
      MYSQL_PASSWORD: root
    ports:
      - '3306:3306'
    volumes:
      - ./tmp/db:/var/lib/mysql

  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/app
    ports:
      - '3000:3000'
    depends_on:
      - db
Gemfile
source 'https://rubygems.org'
gem 'rails', '~>7.0.3'
空のGemfile.lock
entrypoint.sh
#!/bin/bash
set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /app/tmp/pids/server.pid

# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"

2.Rails new

% docker-compose run --rm web rails new . --force --database=mysql --api

3.イメージbuild

% docker-compose build

4.database.ymlの設定

config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: password
  host: db

5.DBのcreate,migration

% docker-compose run --rm web rails db:create
Creating rails_backend_web_run ... done
Created database 'app_development'
Created database 'app_test'

% docker-compose run --rm web rails db:migration

6.コンテナ起動

% docker-compose up -d

http://localhost:3000/ にアクセスし、Railsの画面がでればOK

Graphql

参考
graphql-rubyでAPIを作成
Rails + GraphQLでAPI作成

準備

graphqlのインストール

Gemfile
gem 'graphql'    #追加
% bundle install
% rails generate graphql:install   #様々なファイルが作成されます

上記コマンドで記述されているか確認する

routes.rb
Rails.application.routes.draw do
  post "/graphql", to: "graphql#execute" # rails generate graphql:installで記述されているか確認
  # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html

  # Defines the root path route ("/")
  # root "articles#index"
end

動作確認

Altair GraphQL Clientをインストールして、下記のようにリクエストを送信しHello World!が表示されればOK。

スクリーンショット 2023-01-05 9.16.30.png

モデル作成

% rails g model user

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

      t.timestamps
    end
  end
end

% rails db:migrate

型ファイルの作成

% rails g graphql:object User
   create  app/graphql/types/user_type.rb

上記コマンドを実行し、先程作成したモデルに合わせて以下ファイルが生成されます。

app/graphql/types/user_type.rb
# frozen_string_literal: true

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

Queryの作成

Query: SQLでいうSELECTにあたるもの。データを取得する際に使用。

graphql/type/query_type.rb に下記のように記述します。

graphql/type/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.
    field :users, resolver: Resolvers::QueryTypes::UsersResolver # 追加
    # fieeld: クラスメソッド。データをDBからもってくる単位
    # 追加した記述でリゾルバ(問い合わせを実行するメソッド)を実行
  end
end

app/graphql/resolvers/query_types/users_resolver.rbに下記のように記述

app/graphql/resolvers/query_types/users_resolver.rb
module Resolvers::QueryTypes
  class UsersResolver < GraphQL::Schema::Resolver
    type [Types::UserType], null: false
    def resolve
      User.all
    end
  end
end

画像のような結果になっていればOK(Userのレコードは各自作成してください)

スクリーンショット 2023-01-05 10.04.54.png

Argumentを使用し、指定ユーザのデータを取得

Argument: 検索やデータの呼び出しに使う引数。Queryに渡す引数を指定。

graphql/type/query_type.rb にfieldを追加。

graphql/type/query_type.rb
module Types
  class QueryType < Types::BaseObject
    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.
    field :users, resolver: Resolvers::QueryTypes::UsersResolver 
    field :user, resolver: Resolvers::QueryTypes::UserResolver # 追加
    # fieeld: クラスメソッド。データをDBからもってくる単位
    # 追加した記述でリゾルバ(問い合わせを実行するメソッド)を実行
  end
end

app/graphql/resolvers/query_types/users_resolver.rbファイルを作成し、以下のように記述。

app/graphql/resolvers/query_types/users_resolver.rb
module Resolvers::QueryTypes
  class UserResolver < GraphQL::Schema::Resolver
    type Types::UserType, null: false
    argument :id, ID, required: false # 引数。
# 型はapp/graphql/resolvers/query_types/users_resolver.rbを参照

    def resolve(id:)
      User.find(id)
    end
  end
end

以下のようなクエリで指定したIDのユーザ情報を取得

query
query {
  user(id: 1) {
    id
    name
    email
    createdAt #ここに記載したカラムのデータが返ってくる
  }
}

スクリーンショット 2023-01-05 15.00.25.png

また、nameで検索したい場合は以下のように修正

app/graphql/resolvers/query_types/users_resolver.rb
module Resolvers::QueryTypes
  class UserResolver < GraphQL::Schema::Resolver
    type Types::UserType, null: false
    argument :name, String, required: false # 引数。name
# 型はapp/graphql/resolvers/query_types/users_resolver.rbを参照

    def resolve(name:)
      User.find_by(name: name)
    end  
  end
end

query
query {
  user(name: "test2") {
    id
    name
    email
    createdAt
  }
}

結果

スクリーンショット 2023-01-05 15.06.40.png

Mutationの作成

Mutation: SQLでいうINSERT, UPDATE,DELETE。データを作成、変更削除する際に使用。
まずはユーザ作成を実装します。

下記コマンドを実行します。

% rails g graphql:mutation CreateUser

下記ファイルが作成されます。

app/graphql/types/mutation_type.rb
module Types
  class MutationType < Types::BaseObject
    field :create_user, mutation: Mutations::CreateUser
  end
end

同じく自動生成された app/graphql/mutations/create_user.rbを下記のように修正。

app/graphql/mutations/create_user.rb
module Mutations
  class CreateUser < BaseMutation
    graphql_name 'CreateUser'
    field :user, Types::UserType, null: true

    argument :name, String, required: true # 引数
    argument :email, String, required: true # 引数

    def resolve(**args) # **argsに引数がす
      user = User.create!(args)
      {
        user: user
      }
    end
  end
end

以下のmutationを実行

mutation {
  createUser(
    input:{
      name: "user"
      email: "user@email.com"
    }
  ){
    user {
      id
      name 
      email
    }
  }
}

argsの中身は以下のようになっています

[1] pry(#<Mutations::CreateUser>)> args
=> {:name=>"user", :email=>"user@email.com"}

結果

スクリーンショット 2023-01-05 15.41.53.png

終わりに

環境構築から簡単な機能の実装方法をざっとまとめてみました。
今後graphql-railsの設計も学習したいと思います。

1
2
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
1
2