如何在Docker中使用Rails7 API模式结合MySQL来使用GraphQL
文章的内容 de
开始学习GraphQL时,首先想明白为什么要使用GraphQL。
另外,由于学习过程中遇到了很多我以前从未听说过的词汇,所以我想通过这篇文章来记录笔记。
在这篇文章中,我打算从使用Docker进行环境配置开始,一直到记录user的index、show和create。
GraphQL 是什么?
很快,我发现参考资料非常易懂。介绍了一些使用GraphQL的著名服务,非常有趣。
GraphQL是用于API查询的语言,与REST API不同的是,在REST API中,服务器决定返回的数据结构等,而实际上,在客户端使用数据时可以自由获取数据。
由于如今的智能手机和SPA会处理复杂的数据,GraphQL受到了广泛关注。
优点和缺点
优点
-
- フロント側でレスポンスの形式を指定できる
必要なデータのみ取得でき、オーバーフェッチ、アンダーフェッチがなくなる
Swagger等の仕様書が必要なくなる
型があるため堅牢
一度に複数のリソースを取得できる
RESTでいう post/1,post/2のようなリソースを一気に取得できる
缺点
-
- 学習コストがかかる
- キャッシュが REST よりも複雑になる。N+1問題等に気をつける必要あり。
词汇
-
- クエリ言語:Graphqlサーバへの問い合わせ内容を記載した言語
-
- スキーマ言語: Graphqlサーバでのデータの型を記載した言語
-
- リゾルバ: 問い合わせを実行するメソッド
-
- Query: SQLでいうSELECTにあたるもの。データを取得する際に使用
-
- Mutation: SQLでいうINSERT, UPDATE,DELETE。データを作成、変更削除する際に使用
-
- field: クラスメソッド。データをDBからもってくる単位
- Argument: 検索やデータの呼び出しに使う引数。Queryに渡す引数を指定。
实施
环境构建
1. 准备各种文件
创建以下文件
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"]
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
source 'https://rubygems.org'
gem 'rails', '~>7.0.3'
Gemfile.lock 是空的。
#!/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应用
% docker-compose run --rm web rails new . --force --database=mysql --api
3. 形象构建 ɡtǔ)
% docker-compose build
4. 数据库配置文件database.yml的设置。
default: &default
adapter: mysql2
encoding: utf8mb4
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: root
password: password
host: db
创建数据库并进行迁移。
% 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页面,那就没问题。
你还要其他的东西吗?
使用graphql-ruby创建API
使用Rails + GraphQL创建API
准备
GraphQL的安装
gem 'graphql' #追加
% bundle install
% rails generate graphql:install #様々なファイルが作成されます
请确认上述命令是否已经记录。
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客户端,然后按照下面的请求发送方式发送请求,如果显示Hello World!,则表示成功。
模型的构建 de
% 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
执行上述命令后,将会生成以下文件,以与先前创建的模型相匹配。
# 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
创建查询
查询:相当于SQL中的SELECT。用于获取数据时使用。
在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 文件。
module Resolvers::QueryTypes
class UsersResolver < GraphQL::Schema::Resolver
type [Types::UserType], null: false
def resolve
User.all
end
end
end
只要结果像图片那样就可以了(请各自创建用户记录)。
使用Argument来获取指定用户的数据。
参数:用于搜索和调用数据的参数。指定要传递给查询的参数。
在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 文件,并按照以下方式描述。
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 {
user(id: 1) {
id
name
email
createdAt #ここに記載したカラムのデータが返ってくる
}
}
另外,如果您想通过名字进行搜索,请进行以下修改。
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 {
user(name: "test2") {
id
name
email
createdAt
}
}
结果
生成变异
变异:在SQL中对应INSERT、UPDATE、DELETE操作。用于创建、修改和删除数据。
首先,我们将实现用户创建。
执行以下命令。
% rails g graphql:mutation CreateUser
将会创建下列文件。
module Types
class MutationType < Types::BaseObject
field :create_user, mutation: Mutations::CreateUser
end
end
将自动生成的 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 {
createUser(
input:{
name: "user"
email: "user@email.com"
}
){
user {
id
name
email
}
}
}
args的内容如下
[1] pry(#<Mutations::CreateUser>)> args
=> {:name=>"user", :email=>"user@email.com"}
结果 (jié guǒ)
结束
我简要总结了从环境搭建到基本功能实现的方法。
我也希望今后能学习graphql-rails的设计。