在Rails上搭建GraphQL服务器和设置相关工具的步骤

要做的事情

我们将在Rails应用程序中进行GraphQL的初始设置和周边工具的安装。

    1. 进行以下操作以安装graphql gem:

 

    1. 1. 初始化graphql-ruby命令。

 

    1. 2. 修改AppSchema类的配置项。

 

    1. 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
广告
将在 10 秒后关闭
bannerAds