LoginSignup
10
6

More than 3 years have passed since last update.

GraphQL RubyのResolverについて

Posted at

概要

GraphQL Rubyの resolverについてまとめました。

開発環境

resolverを使う前のGraphQL 実装

# == Schema Information
#
# Table name: subject_scores
#
#  id                    :integer
#  subject_name(科目名)   :string
#  user_name(ユーザー名)      :string 
#  score(点数)            :integer
class SubjectScore < ApplicationRecord
end
  • Types class
module Types
  class QueryType < GraphQL::Schema::Object
    field :subject_scores, [SubjectScoreType], 'Returns all subject scores', null: true
  end
end
module Types
  class SubjectScoreType < GraphQL::Schema::Object
    field :id, Integer, null: true
    field :subject_name, String, null: true
    field :user_name, String, null: true
    field :score, Integer, null: true
  end
end
  • Request
subjectScores: {
  id
  subjectName
  userName
  score
}
  • Response (データベースの値がそのまま返却される)
"data": {
  "subjectScores": [
     {"id": 1, "subjectName": "英語", "userName": "太郎1", "score": 25},
     {"id": 1, "subjectName": "英語", "userName": "太郎2", "score": 50},
     {"id": 1, "subjectName": "英語", "userName": "太郎3", "score": 60}
  ]
}

resolverで値を加工して返却する

scoreが30点未満のユーザー名をマスキングしてみます。

resolver パターン1

module Types
  class SubjectScoreType < GraphQL::Schema::Object
    field :id, Integer, null: true
    field :subject_name, String, null: true
    field :user_name, String, null: true
    field :score, Integer, null: true

    def user_name
      if object.score < 30
        '***'
      else
        object.user_name
      end
    end
  end
end
  • Response(30点未満のユーザー名がマスキングされる)
"data": {
  "subjectScores": [
     {"id": 1, "subjectName": "英語", "userName": "***", "score": 25},
     {"id": 1, "subjectName": "英語", "userName": "太郎2", "score": 50},
     {"id": 1, "subjectName": "英語", "userName": "太郎3", "score": 60}
  ]
}

resolver パターン2

module Types
  class SubjectScoreType < GraphQL::Schema::Object
    field :id, Integer, null: true
    field :subject_name, String, null: true
    field :user_name, String, null: true, resolver_method: :user_name_masking_resolver
    field :score, Integer, null: true

    def user_name_masking_resolver
      if object.score < 30
        '***'
      else
        object.user_name
      end
    end
  end
end
  • Response(30点未満のユーザー名がマスキングされる)
"data": {
  "subjectScores": [
     {"id": 1, "subjectName": "英語", "userName": "***", "score": 25},
     {"id": 1, "subjectName": "英語", "userName": "太郎2", "score": 50},
     {"id": 1, "subjectName": "英語", "userName": "太郎3", "score": 60}
  ]
}

resolver パターン3

https://graphql-ruby.org/fields/resolvers.html#using-resolver
fieldresolver属性を使うパターン。
(resolverクラスを別で定義する必要があります)

  • resolverクラスの定義
# app/graphql/resolvers/base.rb
module Resolvers
  class Base < GraphQL::Schema::Resolver
  end
end
module Resolvers
  class MaskingScore < Resolvers::Base
    type String, null: true

    def resolve
      if object.score < 30
        '***'
      else
        object.user_name
      end
    end
  end
end
  • user_namefieldのresolver属性に Resolvers::MaskingScoreを指定します。
module Types
  class SubjectScoreType < GraphQL::Schema::Object
    field :id, Integer, null: true
    field :subject_name, String, null: true
    field :user_name, String, null: true, resolver: Resolvers::MaskingScore
    field :score, Integer, null: true
  end
end
  • Response(30点未満のユーザー名がマスキングされる)
"data": {
  "subjectScores": [
     {"id": 1, "subjectName": "英語", "userName": "***", "score": 25},
     {"id": 1, "subjectName": "英語", "userName": "太郎2", "score": 50},
     {"id": 1, "subjectName": "英語", "userName": "太郎3", "score": 60}
  ]
}

まとめ

この例ではパターン1で十分ですが、
resolverを共通処理化し、複数のfieldでそのresolverを使う場合もあると思います。(実際にありました)
その場合はパターン2、3が有効かと。

10
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
6