Skip to main content

Overview

Sources are a powerful feature that translate business objects with common structures into GraphQL elements. Think of sources as a portion of your schema that is deeply connected to another class in your Ruby application. If your classes follow a pattern, you can create a source for that pattern and translate all similar classes to GraphQL.
Sources work through a hook-based system, allowing you to define how classes are translated into GraphQL objects, inputs, queries, mutations, and subscriptions.

Source Architecture

Sources extend from Rails::GraphQL::Source and use several key mechanisms:

Assignment Validation

Sources validate that they can handle specific classes:
module GraphQL
  class AwesomeSource < GraphQL::Source::Base
    self.abstract = true
    
    validate_assignment('Awesome::Base')
  end
end
The find_for! method locates the appropriate source for a given object:
# From lib/rails/graphql/source.rb
def find_for!(object)
  find_for(object) || raise(::ArgumentError, (+<<~MSG).squish)
    Unable to find a source for "#{object.name}".
  MSG
end

Hook System

Sources use hooks to control the build process. Available hooks include:
  • start - Runs before any other hook
  • object - Creates the GraphQL object type
  • input - Creates the input type
  • query - Adds query fields
  • mutation - Adds mutation fields
  • subscription - Adds subscription fields
step(:object) do
  assigned_class.attributes.each do |attribute, type|
    safe_field(attribute, type)
  end
end

Managing Hooks

Adding Steps

Use step to add hooks:
# Add to the end (runs first due to reverse order)
step(:query) do
  safe_field("awesome_#{base_name}", :string, null: false) do
    before_resolve(:load, base_name)
  end
end

# Add to the beginning (runs last)
step(:query, unshift: true) do
  # This runs after other query steps
end

Controlling Hook Execution

# Skip parent hooks
skip(:object, :input)

Building Sources

Once defined, sources can be built selectively:
module GraphQL
  class UserSource < GraphQL::AwesomeSource
    build_all
  end
end

Skipping Fields

Prevents specific fields from being created:
skip_fields! :secure_token, :internal_id

Schema Attachment

Sources automatically attach to schemas based on namespaces:
# From lib/rails/graphql/source.rb
def attach_fields!(type = :all, from = self)
  schemas.each { |schema| schema.import_into(type, from) }
end

def schemas
  GraphQL.enumerate(namespaces.presence || :base).lazy.filter_map do |ns|
    Schema.find(ns)
  end
end
Fields are automatically added to schemas in the same namespace as the source.

Configuration

Add your source to the global configuration:
# config/initializers/graphql.rb
Rails::GraphQL.config.sources << 'GraphQL::AwesomeSource'
This enables inline source definitions in schemas:
# app/graphql/app_schema.rb
source Awesome::User  # Automatically identifies the proper source

Best Practices

Use safe_field

Prefer safe_field over field in hooks to allow source classes to override fields:
step(:object) do
  safe_field(:name, :string)  # Can be overridden
end

Mark Base as Abstract

Always mark your base source classes as abstract:
class AwesomeSource < GraphQL::Source::Base
  self.abstract = true
end

Selective Building

Only build what you need to avoid schema bloat:
build_object
build_query
# Don't build mutations if read-only

ActiveRecord Integration

Built-in source for ActiveRecord models

Events

Event system for hooks and callbacks

Build docs developers (and LLMs) love