在Rails上搭建GraphQL服务器和设置相关工具的步骤
要做的事情
我们将在Rails应用程序中进行GraphQL的初始设置和周边工具的安装。
-
- 进行以下操作以安装graphql gem:
-
- 1. 初始化graphql-ruby命令。
-
- 2. 修改AppSchema类的配置项。
-
- 3. 设置rubocop-graphql。
- 4. 添加一个rake任务来将模式信息输出到文件中。
安装 graphql gem
用graphqlgem来构建GraphQL服务器。
+ gem 'graphql'
bundle install
2. 执行GraphQL的初始化命令
由于graphqlgem提供了一个用于设置GraphQL开发的命令行工具graphql:install,作为一个Rails生成器,您可以使用它。
rails g graphql:install --skip-graphiql --skip_keeps --api=true --relay=false --skip_mutation_root_type=true
在这里,我正在指定以下选项。
graphiqlは使用しないので–skip-graphiqlを指定
空ディレクトリを維持する.keepファイルは不要なので–skip_keepsを指定
apiモードでの実装にするので–apiオプションをtrueに指定
relayは使用しないので–relayオプションをfalseに指定
mutationは今回使わないのでskip_mutation_root_typeオプションをtrueに指定
生成文件
将在app/graphql目录中创建等操作将执行
$ tree app/graphql/
app/graphql/
├── app_schema.rb
└── types
├── base_argument.rb
├── base_enum.rb
├── base_field.rb
├── base_input_object.rb
├── base_interface.rb
├── base_object.rb
├── base_scalar.rb
├── base_union.rb
└── query_type.rb
会创建GraphQL端点的定义和控制器的模板。
+ post "/graphql", to: "graphql#execute"
class GraphqlController < ApplicationController
# If accessing from outside this domain, nullify the session
# This allows for outside API access while preventing CSRF attacks,
# but you'll have to authenticate your user separately
# protect_from_forgery with: :null_session
def execute
variables = prepare_variables(params[:variables])
query = params[:query]
operation_name = params[:operationName]
context = {
# Query context goes here, for example:
# current_user: current_user,
}
result = AppSchema.execute(query, variables: variables, context: context, operation_name: operation_name)
render json: result
rescue StandardError => e
raise e unless Rails.env.development?
handle_error_in_development(e)
end
private
# Handle variables in form data, JSON body, or a blank value
def prepare_variables(variables_param)
case variables_param
when String
if variables_param.present?
JSON.parse(variables_param) || {}
else
{}
end
when Hash
variables_param
when ActionController::Parameters
variables_param.to_unsafe_hash # GraphQL-Ruby will validate name and type of incoming variables.
when nil
{}
else
raise ArgumentError, "Unexpected parameter: #{variables_param}"
end
end
def handle_error_in_development(e)
logger.error e.message
logger.error e.backtrace.join("\n")
render json: { errors: [{ message: e.message, backtrace: e.backtrace }], data: {} }, status: 500
end
end
3. 更改AppSchema类的设置项
我会在自动生成的app/graphql/app_schema.rb文件中进行设置添加和不必要部分的删除。
class AppSchema < GraphQL::Schema
+ disable_introspection_entry_points unless Rails.env.development?
+
query(QueryType)
+
+ max_complexity 200
+ max_depth 30
+ default_page_size 50
+
- # For batch-loading (see https://graphql-ruby.org/dataloader/overview.html)
- use GraphQL::Dataloader
-
- # GraphQL-Ruby calls this when something goes wrong while running a query:
- def self.type_error(err, context)
- # if err.is_a?(GraphQL::InvalidNullError)
- # # report to your bug tracker here
- # return nil
- # end
- super
- end
-
- # Union and Interface Resolution
- def self.resolve_type(abstract_type, obj, ctx)
- # TODO: Implement this method
- # to return the correct GraphQL object type for `obj`
- raise(GraphQL::RequiredImplementationMissingError)
- end
-
- # Stop validating when it encounters this many errors:
validate_max_errors(100)
end
更改后的文件内容如下:
class AppSchema < GraphQL::Schema
disable_introspection_entry_points unless Rails.env.development?
query(QueryType)
max_complexity 200
max_depth 30
default_page_size 50
validate_max_errors(100)
end
通过正确的配置,可以抑制高负载查询,防止输出不必要的信息,并确保连接到稳固的服务器。
相反,配置不足或设置不当的值可能导致脆弱性和服务不稳定,因此需要根据服务的需求进行适当的配置。
设定值的详细信息
关闭内省入口点
只需要一种选择:
仅需在开发环境中提供GraphQL模式信息的introspection功能,因此在非开发环境中使用disable_introspection_entry_points进行禁用。
最大复杂性
由于GeaphQL具有灵活的查询功能,可以构建复杂的查询。因此,我们将设置一个名为max_complexity的参数,以检测查询的复杂程度并限制其在一定的阈值以下。
- 同様に、リソースをネストとして無限にデータ検索を行う事も可能なのでネストに制限を加えるmax_depthを指定します
默认页面大小
我們預計資源數量會增長,並設定默認的分頁大小為default_page_size。
验证最大错误
设置validate_max_errors参数,当出现非法输入并导致多个验证错误时,限制错误数量并中断验证。
4. rubocop-graphql的配置设置
在Gemfile中添加定义并进行安装。
+ gem "rubocop-graphql"
bundle install
在rubocop的配置文件中添加加载rubocop-graphql的内容。
require:
+ rubocop-graphql
如果运行RuboCop时出现警告,我们会逐步进行修正。
rubocop
在特定的类别中指定禁用
以下的两个类需要定义description的强制性,但是以下的class中没有定义该方法,因此将其禁用。
-
- GraphQL::Schema::Field
- GraphQL::Schema::Argument
- class BaseArgument < GraphQL::Schema::Argument
+ class BaseArgument < GraphQL::Schema::Argument # rubocop:disable GraphQL/ObjectDescription NOTE: `description`は`GraphQL::Schema::Argument`にはない
end
- class BaseField < GraphQL::Schema::Field
+ class BaseField < GraphQL::Schema::Field # rubocop:disable GraphQL/ObjectDescription NOTE: `description`は`GraphQL::Schema::Field`にはない
end
新增一个用于导出模式信息到文件的rake任务
为了在前端开发等方面进行利用,我们将添加一个rake任务,用于将GraphQL模式信息输出到文件中。
由于graphql-rubygem中提供了一个名为GraphQL::RakeTask的类用于添加rails任务,我们将使用该类。
源代码在这里
Rake任务的定义
在`lib/tasks`目录下创建`graphql_schema_dump.rake`文件,并按照以下方式进行定义。
require 'graphql/rake_task'
load_context = Proc do
current_user = User.first
{
current_user:,
}
end
GraphQL::RakeTask.new(schema_name: 'AppSchema', load_context:, directory: 'graphql_schema')
GraphQL::RakeTaskクラスをnewする事でrails taskが追加されます。
schema_nameはアプリケーションで用いているスキーマクラスの名前AppSchema(app/graphql/app_schema.rb)を指定します。
ログイン情報等のコンテキストをスキーマの中で扱っている場合はload_contextを使ってダミーデータをコンテキストに引き渡すProcを指定する必要があります。
ここではDBに存在するUserオブジェクトを取得して引き渡しています。
ファイルを出力するディレクトリをgraphql_schemaに指定します
检查 rake 任务
在增加上述内容之后,rake任务已添加到模式输出中,如下所示。
rails task -T | grep graphql
rails graphql:pro:validate[gem_version] # Get the checksum of a graphql-pro version and compare it to published versions on GitHub and graphql-ruby.org
rails graphql:schema:dump # Dump the schema to JSON and IDL
rails graphql:schema:idl # Dump the schema to IDL in graphql_schema/schema.graphql
rails graphql:schema:json # Dump the schema to JSON in graphql_schema/schema.json
新增的 rake 任务的详细信息
Ruby on Rails GraphQL: Pro 验证 [gem_version]
- Proバージョンを使用している場合にライセンスが有効化の検証をする
生成Rails GraphQL模式文件
- スキーマをIDLとJSON形式両方でそれぞれ出力する
rails graphql:schema:idl 可以用中文翻译为:”Rails GraphQL模式的接口定义语言(Interface Definition Language)”。
- スキーマをIDL形式で出力する
用原生的中文进行释义,只需要一种选择:
rails graphql:schema:json
翻译为:用Rails命令生成GraphQL的模式(schema)的JSON文件。
- スキーマをJSON形式で出力する
请使用以下一种方式进行描述原文内容:
– 引用
– 借鉴
– 查考
– 提及
-
- https://github.com/rmosolgo/graphql-ruby
-
- https://github.com/DmitryTsepelev/rubocop-graphql
-
- https://graphql-ruby.org/
- https://graphql.org/
软件开发环境
-
- graphql (2.1.0)
-
- rails 7.0.8
- ruby 3.2.2p53