Rails + GraphQL w/ Auth
こちらの記事を参考にメモとして
まずAPIモードでプロジェクト作成
rails new rails-graphql --api
Gemfileを記述
gem 'graphql'
gem 'graphiql-rails'
gem 'sprockets', '< 4'
sprocketsの4系だと動かないので、とりあえず4未満、3系の最新をいれるようにする
config/application.rb
の# require "sprockets/railtie"
のコメントアウトをはずす
必要なGemをインストールする。bundlerがなければbundlerもインスコする
gem install graphql graphiql-rails bundler
bundle install
rails generate graphql:install
これでだいたいのセットアップは終わり
当たり前のことだけど、わかってなければ、sudoは使わないこと。対応できるならまあいいけど
Queryの作成
GraphQLにはQueryという概念がある。まずはそれの作成から
rails g model Post title:string description:text
rake db:migrate
テストデータを追加する。
rails c
> Post.create(title: "What is Ruby?", description:"Ruby is a programming language")
> Post.create(title: "How to learn Ruby", description:"Read some books brah")
>
は含めずコマンドを打ってね
先程作成したモデルに沿うようにGraphQL用の型を追加する
rails g graphql:object Post id:ID! title:String! description:String!
app/graphql/types/post_type.rb
を見てみると、こんな感じで最初エグいことになってるかもしれない。
module Types
class PostType < Types::BaseObject
field :id, ID, null: false
field :title, String, null: true
field :description, String, null: true
field :created_at, GraphQL::Types::ISO8601DateTime, null: false
field :updated_at, GraphQL::Types::ISO8601DateTime, null: false
field :id, ID, null: false
field :title, String, null: false
field :description, String, null: false
end
end
理由はわからないけど、多分graphqlライブラリの最初からあるExample用のモデルとかぶるためだと思われる。これらはいまは必要ないので、修正する。
module Types
class PostType < Types::BaseObject
field :id, ID, null: false
field :title, String, null: false
field :description, String, null: false
end
end
こうなればおk
Query Resolverを書く。ResolverっていうのはGraphQLでの概念として説明すると、QueryやMutationを行う際にそのオペレーションがなにを使うのかみたいなのを解決するやつ(多分)。Resolveは解決っていう意味です。
module Types
class QueryType < Types::BaseObject
field :posts, [Types::PostType], null: false
def posts
Post.all
end
field :post, Types::PostType, null: false do
argument :id, Int, required: false
end
def post(id:)
Post.find(id)
end
end
end
丸コピでおk
config/routes.rb
に以下を追加。
if Rails.env.development?
# add the url of your end-point to graphql_path.
mount GraphiQL::Rails::Engine, at: "/graphiql", graphql_path: "/graphql"
end
一応、こちらの環境ではこんな感じに。
Rails.application.routes.draw do
post "/graphql", to: "graphql#execute"
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
if Rails.env.development?
# add the url of your end-point to graphql_path.
mount GraphiQL::Rails::Engine, at: "/graphiql", graphql_path: "/graphql"
end
end
コメントとかは、必要でなければ消しちゃっても構いません。
Mutationの作成
rails g graphql:mutation CreatePost
余談だが、g
はgenerate
のショートハンド(短縮形)です
上記のコマンドは以下の2つの事を行います。
- (1)graphql/mutations/create_post.rbの作成。
- (2)field :createPost, mutation: Mutations::CreatePostをgraphql/types/mutations_type.rbに追記する。
らしい。
参考記事に沿って、
module Mutations
class CreatePost < GraphQL::Schema::RelayClassicMutation
graphql_name 'CreatePost'
field :post, Types::PostType, null: true
field :result, Boolean, null: true
argument :title, String, required: false
argument :description, String, required: false
def resolve(**args)
post = Post.create(title: args[:title], description: args[:description])
{
post: post,
result: post.errors.blank?
}
end
end
end
こんな感じに書く。
プロジェクトルートでrails s
してみて、http://localhost:3000/graphiql
にアクセスし、以下を入力
mutation A {
createPost(
input: {
title: "title1"
description: "description1"
}
){
post {
id
title
description
}
}
}
query B {
posts {
id
title
}
}
mutation A
を実行してみる。結果はこんな感じ
{
"data": {
"createPost": {
"post": {
"id": 3,
"title": "title1",
"description": "description1"
}
}
}
}
idはシーケンシャルに変わるので3じゃない可能性もあります。
更新用のMutationを作成する。
rails g graphql:mutation UpdatePost
そのあと、更新用のMutationの修正
module Mutations
class UpdatePost < GraphQL::Schema::RelayClassicMutation
graphql_name 'UpdatePost'
field :post, Types::PostType, null: true
field :result, Boolean, null: true
argument :id, ID, required: true
argument :title, String, required: false
argument :description, String, required: false
def resolve(**args)
post = Post.find(args[:id])
post.update(title: args[:title], description: args[:description])
{
post: post,
result: post.errors.blank?
}
end
end
end
また余談だが、今どきの(?)Railsはホットリロードに対応しているので、別のウィンドウないしタブでターミナルを開いたままコマンドを実行とかでそのままコードの更新が引き継がれる。
そしたら、さっきと同じ感じでhttp://localhost:3000/graphiqlにアクセスして、以下を実行
mutation {
updatePost(
input:{
id: 1
title: "Updated"
description: "Updated"
}
){
post {
id
title
description
}
}
}
結果はこう
{
"data": {
"updatePost": {
"post": {
"id": "1",
"title": "Updated",
"description": "Updated"
}
}
}
}
今回は、削除については割愛する。というのも、RailsでDBを操作する方法は定型化されていて、書くMutation Typeも似たようなものなので、どうしても書きたければ元記事を参照してください(面倒くさかった)。
認証機能の実装
とりあえず予定としては、register、login、認証付きリクエスト、認証用Mutationを作る感じ
参考予定