Rails로 GraphiQL API 만들기 자습서 [graphiql-ruby]
래일스를 이용해 그라피QL의 API를 빠르게 제작하자는 취지로 제작됐다.
2021년 5월 2일 시점의 최신 Version입니다.
ruby: 3.0.1
rails: 6.1.3.1
graphql-ruby: 1.12.8
GraphiQL 설정
API 모드
rails new
.minitest를 사용하지 않기 때문에 닫혔습니다.
$ rails new rails-graphql-api -T --api -d postgresql
GraphiQL Ruby 가져오기
Gemfile.rb
# Gemfile
+ gem 'graphql'
$ bundle install
이어서 bin/rails g graphql:install
를 실행하고 필요한 파일을 설정합니다.$ bin/rails g graphql:install
실행 결과$ bin/rails g graphql:install
Running via Spring preloader in process 50049
create app/graphql/types
create app/graphql/types/.keep
create app/graphql/rails_graphql_api_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"
Skipped graphiql, as this rails project is API only
You may wish to use GraphiQL.app for development: https://github.com/skevy/graphiql-app
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/rails_graphql_api_schema.rb
GraphiQL IDE 가져오기
GraphiQL API의 동작을 확인하기 위해 GraphiQL을 추가합니다.
입력 방법에는 응용 프로그램과 Gem 두 가지가 있습니다.
※ API 모드가 아닌 경우 그래피ql-rails에 가입한 상태
bin/rails g graphql:install
에서 실행하면 자동으로 설정됩니다.IDE에서 Sprockets를 사용하기 위해 미묘하게 프로그램을 설치하는 방법을 선택했습니다.
GraphiQL은 페이스북제지만 Prism제GraphQL Playground와 Apollo제Apollo Studio 등 효율적으로 GraphiQL을 개발하는 도구가 끊임없이 등장하고 있다.
GraphiQL만 사용해 봤기 때문에 다른 IDE들도 사용해 보려고 합니다.
1. GraphiQL 응용 프로그램 설치
brew cask를 통해 설치합니다.
$ brew install --cask graphiql
설치가 완료되면 GraphiQL을 엽니다.이럴 때는 안전성과 프라이버시가 차단되기 때문에 허용됩니다.
GraphiQL Endpoint에
http://localhost:3000/graphql
를 입력합니다.제너레이트가 하면 샘플쿼리로 테스트필드를 준비했기 때문에 실행 가능한지 확인합니다.
메뉴 모음의▶ 실행에 따르다.
{
testField
}
2. Gem 기반 설치
Gem 기반 설치 방법
Rails에 GraphiQL IDE를 사용할 수 있는 graphiql-rails를 추가합니다.
Gemfile
gem 'graphiql-rails'
경로/graphiql
를 편집하여 GraphiQLroutes.rb
을 표시합니다.config/routes.rb
# 以下を追加
if Rails.env.development?
mount GraphiQL::Rails::Engine, at: "/graphiql", graphql_path: "/graphql"
end
이어서 Sprockets를 사용하여 GraphiQL의 화면을 설정합니다.API 모드의 경우 Sprockets가 비활성화되어 활성화됩니다.
Note on API Mode
If you're using Rails 5 in "API mode", you'll also need to add require "sprockets/railtie"to your application.rb.
config/application.rb
- # require "sprockets/railtie"
+ require "sprockets/railtie"
sprockets 제작에 필요한 manifest.이번에는 개발환경 스프록스만 사용하기 때문에 안은 비어 있어 문제없습니다.
$ mkdir -p app/assets/config && touch app/assets/config/manifest.js
assets 파일을 만들고 개발 환경에서GraphiQL의assets를 읽습니다.$ touch app/initializers/assets.rb
config/initializers/assets.rbif Rails.env.development?
Rails.application.config.assets.precompile += %w[graphiql/rails/application.js
graphiql/rails/application.css]
end
$ bin/rails s
http://localhost:3000/graphiql 다음 화면을 표시하면 됩니다.해보자Query
모델 생성
Post 및 Comment 모델을 만듭니다.
$ bin/rails g model post title:string body:text
$ bin/rails g model comment post:references body:text
를 각 열에 추가null: false
.# xxxx_create_posts.rb
class CreatePosts < ActiveRecord::Migration[6.1]
def change
create_table :posts do |t|
t.string :title, null: false
t.text :body, null: false
t.timestamps
end
add_index :posts, :created_at
end
end
# xxxx_create_comments.rb
class CreateComments < ActiveRecord::Migration[6.1]
def change
create_table :comments do |t|
t.references :post, null: false, foreign_key: true
t.text :body, null: false
t.timestamps
end
end
end
Object Type 제작
그런 다음 포스트와 Comment 유형을 만듭니다.
모델과 같은 이름으로 제작하면 각 열과 유형에 자동으로 덧붙인다.
has-many 등은 읽을 수 없기 때문에 스스로 설정합니다.
bin/rails g graphql:object 型名 カラム名:型
에서 생성됩니다.$ bin/rails g graphql:object post comments:Comment
$ bin/rails g graphql:object comment
app/graphql/types/post_type.rbmodule Types
class PostType < Types::BaseObject
field :id, ID, null: false
field :title, String, null: false
field :body, String, null: false
- field :comments, Types::CommentType, null: true
+ field :comments, [Types::CommentType], null: false
field :created_at, GraphQL::Types::ISO8601DateTime, null: false
field :updated_at, GraphQL::Types::ISO8601DateTime, null: false
end
end
app/graphql/types/comment_type.rbmodule Types
class CommentType < Types::BaseObject
field :id, ID, null: false
- field :post_id, Integer, null: false
+ field :post, Types::PostType, null: false
field :body, String, null: false
field :created_at, GraphQL::Types::ISO8601DateTime, null: false
field :updated_at, GraphQL::Types::ISO8601DateTime, null: false
end
end
Query 만들기
포스트를 가져오는 Query를
query_type.rb
에 작성합니다.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
+ field :post, Types::PostType, null: false do
+ description 'Find a post by ID'
+ argument :id, ID, required: true
+ end
+
+ def post(id:)
+ Post.find(id)
+ end
end
end
얻을 수 있는지 없는지를 시험하기 위해 데이터를 만들다.$ bin/rails c
post = Post.create(title: 'test', body: 'body')
post.comments.create(body: 'comment 1')
post.comments.create(body: 'comment 2')
GraphiQL을 사용하여Query를 실행합니다.query {
post(id: "1") {
id
title
body
comments {
id
body
}
}
}
Post 및 Post와 연결된 Comments 확보🎉
Resolver로 바꿔볼게요.
query_type.rb
점점 비대해지기 때문에 수량이 증가하는 상황에서 또는 복잡한 획득 방법을 통해 Resolver 형태로 분리된다.처음부터 Resolver 형식을 자주 사용하는 것도 좋다.
Resolvers 디렉토리를 생성합니다.
$ mkdir app/graphql/resolvers
기타 기본 상황에 따라 기본 정보를 작성한다.app/graphql/resolvers/base_resolver.rb
module Resolvers
class BaseResolver < GraphQL::Schema::Resolver
argument_class Types::BaseArgument
end
end
post_resolver.rb
.def resolve ... end
반환할 데이터 처리resolve의 매개 변수에argument의 값(여러 개가 있을 경우 여러 개가 들어간다)이 포함되어 있기 때문에
resolve(id:)
또는 resolve(**args)
의 형식으로 매개 변수를 받아들인다.app/graphql/resolvers/post_resolver.rb
module Resolvers
class PostResolver < Resolvers::BaseResolver
description 'Find a post by ID'
type Types::PostType, null: false
argument :id, ID, required: true
def resolve(id:)
Post.find(id)
end
end
end
query_type.rb
의field :post
를resolver의 형식으로 개작하다.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
+ field :post, resolver: Resolvers::PostResolver
- field :post, Types::PostType, null: false do
- description 'Find a post by ID'
- argument :id, ID, required: true
- end
-
- def post(id:)
- Post.find(id)
- end
end
end
이렇게 하면 Resolver에서 취득하는 것으로 변경할 수 있다.GraphiQL에서 같은 Query를 사용하여 얻을 수 있는지 확인하십시오.
Mutation을 해보도록 하겠습니다.
Create Post Mutation
다음은 포스트 메이킹을 위한 뮤테이션을 제작한다.
g graphql:mutation
로 제작하면 mutation_type.rb
와 create_post.rb
로 추가 제작됩니다.$ bin/rails g graphql:mutation create_post
실행 결과$ bin/rails g graphql:mutation create_post
Running via Spring preloader in process 56616
exist app/graphql/mutations
identical app/graphql/mutations/.keep
identical app/graphql/mutations/base_mutation.rb
skip app/graphql/types/mutation_type.rb
add_root_type mutation
create app/graphql/mutations/create_post.rb
gsub app/graphql/types/mutation_type.rb
app/graphql/types/mutation_post.rbmodule Types
class MutationType < Types::BaseObject
+ field :create_post, mutation: Mutations::CreatePost
end
end
create_post.rb
편집합니다.field는 반환 값을 지정합니다.
resolve의 반환값은field의 반환값에 따라 산열 형식으로 반환됩니다.
app/graphql/mutations/create_post.rb
module Mutations
class CreatePost < BaseMutation
+ field :post, Types::PostType, null: false
+
+ argument :body, String, required: true
+ argument :title, String, required: true
+
+ def resolve(**params)
+ post = Post.create!(params)
+ { post: post }
+ end
end
end
GraphiQL로 해보세요.mutation ($input: CreatePostInput!) {
createPost(input: $input) {
post {
title
body
}
}
}
왼쪽 아래에 있는 QUERY VAIABLES를 클릭하면 입력할 수 있습니다.variables
{
"input": {
"title": "new title",
"body": "new body"
}
}
새 포스트가 작성됨🎉
InputObject에서 설치
arguument는 InputObject를 사용하여 요약하여 공통화할 수 있습니다.
UpdatePost의 InputObject를 사용해 보십시오.
inputs 디렉토리를 만듭니다.
$ mkdir app/graphql/types/inputs
BaseInputObject가 이미 있기 때문에 제작post_input_type.rb
했습니다.app/graphql/types/inputs/post_input_type.rb
module Types
module Inputs
class PostInputType < Types::BaseInputObject
argument :id, Int, required: true
argument :body, String, required: false
argument :title, String, required: false
end
end
end
이어 제작update_post.rb
.$ bin/rails g graphql:mutation update_post
app/graphql/types/mutation_post.rbmodule Types
class MutationType < Types::BaseObject
field :create_post, mutation: Mutations::CreatePost
+ field :update_post, mutation: Mutations::UpdatePost
end
end
PostInputType을argument에 건네주면params는 PostInputType의 유형을 가질 수 있습니다.app/graphql/mutations/update_post.rb
module Mutations
class UpdatePost < Mutations::BaseMutation
+ argument :params, Types::Inputs::PostInputType, required: true
+
+ def resolve(params:)
+ post_params = params.to_h
+ post = Post.find(post_params.delete(:id))
+ post.update!(post_params.compact)
+ post
+ end
end
end
GraphiQL로 실행해 보세요.mutation ($params: UpdatePostInput!) {
updatePost(input: $params) {
post {
id
title
body
}
}
}
variables{
"input": {
"params": {
"id": 1,
"title": "update title"
}
}
}
포스트 타이틀 변경됨🎉
InputObject는 공동화하고 싶은argment가 설립될 때 만들 수 있으면 좋겠다고 생각했어요.
참고 자료
Reference
이 문제에 관하여(Rails로 GraphiQL API 만들기 자습서 [graphiql-ruby]), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/necocoa/articles/setup-graphql-ruby텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)