or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

dataloader-performance.mdindex.mdquery-execution.mdschema-definition.mdtype-system.md
tile.json

schema-definition.mddocs/

Schema Definition

Core classes and methods for defining GraphQL schemas, including schema setup, object types, fields, arguments, and type relationships in GraphQL Ruby.

Capabilities

Schema Class

The root schema class that ties together all GraphQL types and provides the execution interface.

class GraphQL::Schema
  # Configure root types
  def self.query(query_type)
  def self.mutation(mutation_type)
  def self.subscription(subscription_type)
  
  # Schema configuration
  def self.max_depth(value)
  def self.max_complexity(value)
  def self.default_max_page_size(value)
  def self.orphan_types(*types)
  def self.use(plugin, **options)
  
  # Execution interface
  def self.execute(query_string, variables: {}, context: {}, operation_name: nil, only: nil, except: nil)
  def self.multiplex(queries, context: {}, max_complexity: nil)
  
  # Introspection and utilities
  def self.get_type(type_name)
  def self.types(context = GraphQL::Query::NullContext.instance)
  def self.to_definition
  def self.to_json(**args)
end

Usage Examples:

class MySchema < GraphQL::Schema
  query QueryType
  mutation MutationType
  subscription SubscriptionType
  
  # Configuration
  max_depth 15
  max_complexity 1000
  use GraphQL::Dataloader
  use GraphQL::Subscriptions::ActionCableSubscriptions
  
  # Custom error handling
  def self.type_error(err, context)
    # Handle type resolution errors
    GraphQL::ExecutionError.new("Type error: #{err.message}")
  end
  
  # Authorization callback
  def self.unauthorized_object(err)
    raise GraphQL::ExecutionError, "Unauthorized access"
  end
end

# Execute queries
result = MySchema.execute(
  'query GetUser($id: ID!) { user(id: $id) { name email } }',
  variables: { id: "123" },
  context: { current_user: current_user }
)

Object Types

Define GraphQL object types that represent data structures in your API.

class GraphQL::Schema::Object
  # Type metadata
  def self.description(text)
  def self.graphql_name(name)
  
  # Field definitions
  def self.field(name, type, null:, description: nil, deprecation_reason: nil, &block)
  def self.fields
  
  # Interface implementation
  def self.implements(*interfaces)
  def self.interfaces
  
  # Authorization
  def self.authorized?(object, context)
  def self.scope_items(items, context)
  
  # Introspection helpers  
  def self.visible?(context)
  def self.accessible?(context)
end

Usage Examples:

class UserType < GraphQL::Schema::Object
  description "A user in the system"
  
  field :id, ID, null: false, description: "Unique identifier"
  field :name, String, null: true, description: "Display name"
  field :email, String, null: false, description: "Email address"
  field :created_at, GraphQL::Types::ISO8601DateTime, null: false
  field :posts, [PostType], null: true, description: "User's posts"
  
  # Custom field with arguments
  field :posts_by_status, [PostType], null: true do
    argument :status, PostStatusEnum, required: true
    argument :limit, Integer, required: false, default_value: 10
  end
  
  # Resolver methods
  def posts_by_status(status:, limit: 10)
    object.posts.where(status: status).limit(limit)
  end
  
  # Authorization
  def self.authorized?(user, context)
    context[:current_user]&.can_view?(user)
  end
  
  # Custom field authorization
  field :private_notes, String, null: true do
    def authorized?(object, args, context)
      context[:current_user] == object
    end
  end
end

Field Definitions

Individual field specifications with types, arguments, and resolver logic.

class GraphQL::Schema::Field
  def initialize(name, type, null:, description: nil, deprecation_reason: nil)
  
  # Arguments
  def argument(name, type, required: false, default_value: nil, description: nil)
  def arguments
  
  # Metadata
  def description(text = nil)
  def deprecation_reason(reason = nil)
  
  # Authorization and visibility
  def authorized?(object, args, context)
  def visible?(context)
  
  # Execution hooks
  def resolve(object, args, context)
end

Usage Examples:

# Field with complex arguments
field :search_posts, [PostType], null: false do
  description "Search posts with filters and pagination"
  
  argument :query, String, required: false, description: "Text search query"
  argument :category_ids, [ID], required: false, description: "Filter by categories"
  argument :published_after, GraphQL::Types::ISO8601DateTime, required: false
  argument :limit, Integer, required: false, default_value: 20
  argument :offset, Integer, required: false, default_value: 0
end

def search_posts(query: nil, category_ids: nil, published_after: nil, limit: 20, offset: 0)
  scope = Post.published
  scope = scope.where("title ILIKE ?", "%#{query}%") if query
  scope = scope.where(category_id: category_ids) if category_ids&.any?
  scope = scope.where("published_at > ?", published_after) if published_after
  scope.limit(limit).offset(offset)
end

# Field with authorization
field :admin_notes, String, null: true do
  description "Internal admin notes (admin only)"
  
  def authorized?(object, args, context)
    context[:current_user]&.admin?
  end
end

Arguments

Define and validate arguments for GraphQL fields and mutations.

class GraphQL::Schema::Argument
  def initialize(name, type, description: nil, required: false, default_value: nil)
  
  # Properties
  def type
  def required?
  def optional?
  def default_value
  def description
  
  # Validation and preparation
  def prepare_value(object, value, context)
  def authorized?(object, value, context)
end

Usage Examples:

# Custom argument preparation
class UserSearchType < GraphQL::Schema::InputObject
  argument :name, String, required: false do
    description "Name to search for"
    
    def prepare_value(object, value, context)
      # Normalize the search value
      value&.strip&.downcase
    end
  end
  
  argument :email_domain, String, required: false do
    def authorized?(object, value, context)
      # Only admins can search by email domain
      context[:current_user]&.admin?
    end
  end
end

# Field using custom input
field :search_users, [UserType], null: false do
  argument :filters, UserSearchType, required: false
  argument :limit, Integer, required: false, default_value: 50
end

def search_users(filters: nil, limit: 50)
  scope = User.all
  if filters
    scope = scope.where("LOWER(name) LIKE ?", "%#{filters[:name]}%") if filters[:name]
    scope = scope.where("email LIKE ?", "%@#{filters[:email_domain]}") if filters[:email_domain]
  end
  scope.limit(limit)
end

Input Objects

Define input types for mutations and complex field arguments.

class GraphQL::Schema::InputObject
  # Argument definitions
  def self.argument(name, type, required: false, default_value: nil, description: nil)
  def self.arguments
  
  # Metadata
  def self.description(text)
  def self.graphql_name(name)
  
  # Conversion helpers
  def to_h
  def to_hash
  def [] (key)
  
  # Validation hooks
  def self.coerce_input(value, context)
  def self.coerce_result(value, context)
end

Usage Examples:

class CreateUserInput < GraphQL::Schema::InputObject
  description "Input for creating a new user"
  
  argument :name, String, required: true, description: "User's display name"
  argument :email, String, required: true, description: "User's email address"
  argument :password, String, required: true, description: "User's password"
  argument :role, UserRoleEnum, required: false, default_value: "USER"
  argument :metadata, GraphQL::Types::JSON, required: false
  
  # Custom validation
  def self.coerce_input(value, context)
    input = super
    
    # Validate email format
    unless input[:email] =~ URI::MailTo::EMAIL_REGEXP
      raise GraphQL::CoercionError, "Invalid email format"
    end
    
    # Validate password strength
    if input[:password].length < 8
      raise GraphQL::CoercionError, "Password must be at least 8 characters"
    end
    
    input
  end
end

# Usage in mutation
class CreateUser < GraphQL::Schema::Mutation
  argument :input, CreateUserInput, required: true
  
  field :user, UserType, null: true
  field :errors, [String], null: false
  
  def resolve(input:)
    user = User.create(input.to_h)
    if user.persisted?
      { user: user, errors: [] }
    else
      { user: nil, errors: user.errors.full_messages }
    end
  end
end

Interfaces

Define shared fields across multiple object types.

class GraphQL::Schema::Interface
  include GraphQL::Schema::Interface
  
  # Field definitions (same as Object)
  def self.field(name, type, null:, description: nil)
  def self.fields
  
  # Type resolution
  def self.resolve_type(object, context)
  
  # Implementation checking
  def self.coerce_input(value, context)
  def self.coerce_result(value, context)
end

Usage Examples:

module NodeInterface
  include GraphQL::Schema::Interface
  description "An object with a global ID"
  
  field :id, ID, null: false, description: "Global object identifier"
  
  def self.resolve_type(object, context)
    case object
    when User then UserType
    when Post then PostType
    when Comment then CommentType
    else
      raise GraphQL::RequiredImplementationMissingError, "Unknown type: #{object.class}"
    end
  end
end

# Implementing the interface
class UserType < GraphQL::Schema::Object
  implements NodeInterface
  
  # id field is inherited from NodeInterface
  field :name, String, null: true
  field :email, String, null: false
end

class PostType < GraphQL::Schema::Object
  implements NodeInterface
  
  field :title, String, null: false
  field :content, String, null: true
  field :author, UserType, null: false
end