A GraphQL::Schema::Resolver is a container for field signature and resolution logic. It can be attached to a field with the resolver: keyword:

# Use the resolver class to execute this field
field :pending_orders, resolver: PendingOrders

Under the hood, GraphQL::Schema::Mutation is a specialized subclass of Resolver.

First, ask yourself …

Do you really need a Resolver? Putting logic in a Resolver has some downsides:

Here are a few alternatives to consider:

field :recommended_items, [Types::Item], null: false
def recommended_items context[:viewer]).items
# Generate a field which returns a filtered, sorted list of items
def self.items_field(name, override_options)
  # Prepare options
  default_field_options = { type: [Types::Item], null: false }
  field_options = default_field_options.merge(override_options)
  # Create the field
  field(name, field_options) do
    argument :order_by, Types::ItemOrder, required: false
    argument :category, Types::ItemCategory, required: false
    # Allow an override block to add more arguments
    yield if block_given?

# Then use the generator to create a field:
items_field(:recommended_items) do
  argument :similar_to_product_id, ID, required: false
# Implement the field
def recommended_items
  # ...

As a matter of code organization, that class method could be put in a module and shared between different classes that need it.

module HasRecommendedItems
  def self.included(child_class)
    # attach the field here
    child_class.field(:recommended_items, [Types::Item], null: false)

  # then implement the field
  def recommended_items
    # ...

# Add the field to some objects:
class Types::User < BaseObject
  include HasRecommendedItems # adds the field

When do you really need a resolver?

So, if there are other, better options, why does Resolver exist? Here are a few specific advantages:

Using resolver

To add resolvers to your project, make a base class:

# app/graphql/resolvers/base.rb
module Resolvers
  class Base < GraphQL::Schema::Resolver
    # if you have a custom argument class, you can attach it:
    argument_class Arguments::Base

Then, extend it as needed:

module Resolvers
  class RecommendedItems < Resolvers::Base
    type [Types::Item], null: false

    argument :order_by, Types::ItemOrder, required: false
    argument :category, Types::ItemCategory, required: false

    def resolve(order_by: nil, category: nil)
      # call your application logic here:
      recommendations =
        viewer: context[:viewer],
        recommended_for: object,
        order_by: order_by,
        category: category,
      # return the list of items

And attach it to your field:

class Types::User < Types::BaseObject
  field :recommended_items,
    resolver: Resolvers::RecommendedItems,
    description: "Items this user might like"

Since the Resolver lifecycle is managed by the GraphQL runtime, the best way to test it is to execute GraphQL queries and check the results.