Skip to main content

Overview

The TypeMap is Rails GraphQL’s central registry for all GraphQL types, directives, and schemas. Inspired by ActiveRecord::Type::TypeMap, it stores items with their unique names, basic settings, and indexes them for easy retrieval. Items are stored as procs so aliases can fetch the base object even if it changes later.

Cache Structure

Namespace -> BaseClass -> ItemKey -> Item

Base Classes

The TypeMap manages three base classes:
  • :Type - All GraphQL types (scalars, objects, interfaces, unions, enums, inputs)
  • :Directive - GraphQL directives
  • :Schema - GraphQL schemas

Instance Methods

version

type_map.version
# => "a1b2c3d4"
Get the current version of the TypeMap. On each reset, the version changes and can be used to invalidate cache. Uses the first 8 characters of GraphQL.config.version or generates a random hex.

reset!

type_map.reset!
Reset the state of the type mapper. Clears all registered objects, pending registrations, callbacks, and dependencies. Called automatically during initialization.

register

type_map.register(UserType)
object
Class
required
A class where the namespaces and base class can be inferred. Must include Helpers::Registerable.
Register a given object. The object is indexed by:
  • Its base namespace and key
  • Its name
  • All aliases
  • Additional namespaces (if any)
Returns the registered object.

unregister

type_map.unregister(UserType, PostType)
objects
Class
required
One or more objects to unregister.
Unregister the provided objects by assigning nil to their final value in the index.

register_alias

type_map.register_alias('User', 'Person', base_class: :Type, namespace: :v2)
type_map.register_alias('CustomDate', base_class: :Type) { DateScalar }
name_or_key
String | Symbol
required
The alias name or key to register.
key
String | Symbol
The key from the same namespace and base class to alias. Mutually exclusive with block.
base_class
Symbol
default:":Type"
The base class for the alias (:Type, :Directive, or :Schema).
namespace
Symbol | Array<Symbol>
Namespace(s) where the alias should be registered.
Register an item alias. Provide either a key from the same namespace/base class, or a block that returns the item.

fetch

type_map.fetch('User', base_class: :Type, namespace: :v2)
type_map.fetch(:string_scalar, fallback: :String)
key_or_name
String | Symbol | Array
required
The key or name to find. Can be an array of possibilities.
base_class
Symbol
default:":Type"
The base class to search within.
namespace
Symbol | Array<Symbol>
Namespace(s) to search. Automatically includes :base unless exclusive: true.
exclusive
Boolean
default:"false"
If true, only search the specified namespace(s), not :base.
fallback
String | Symbol
Alternative key/name to try if the primary one isn’t found.
prevent_register
Boolean | Array
Prevent registration of pending items during fetch. Can specify specific items to skip.
Find the given key or name inside the base class either in the given namespace or the :base namespace. Returns nil if not found.

fetch!

type_map.fetch!('User', base_class: :Type)
# => UserType

type_map.fetch!('NonExistent')
# => Rails::GraphQL::NotFoundError: Unable to find "NonExistent" Type object.
Same as fetch but raises NotFoundError if the item isn’t found. Will attempt to load dependencies and retry before failing.

exist?

type_map.exist?('User', base_class: :Type, namespace: :v2)
# => true
name_or_key
String | Symbol
required
The name or key to check.
base_class
Symbol
default:":Type"
The base class to check within.
namespace
Symbol | Array<Symbol>
Namespace(s) to check. Includes :base unless exclusive: true.
exclusive
Boolean
default:"false"
If true, only check the specified namespace(s).
Checks if a given key or name is already defined under the same base class and namespace.

object_exist?

type_map.object_exist?(UserType)
# => true
object
Class
required
The object to check for existence.
Find if a given object is already defined. Automatically infers the base class and namespaces from the object.

each_from

type_map.each_from(:v2, base_class: :Type) do |type|
  puts type.gql_name
end

# Or as lazy enumerator
enum = type_map.each_from([:v2, :v3], base_classes: [:Type, :Directive])
namespaces
Symbol | Array<Symbol>
required
Namespace(s) to iterate over.
base_class
Symbol
Specific base class to iterate. Can use base_classes for multiple.
base_classes
Array<Symbol>
Multiple base classes to iterate over.
exclusive
Boolean
default:"false"
If true, only iterate the specified namespace(s).
Iterate over types/directives/schemas defined in the given namespaces. Returns a lazy enumerator if no block is given.

objects

type_map.objects
# => [UserType, PostType, StringScalar, ...]

type_map.objects(base_classes: [:Type], namespaces: [:v2])
# => [UserTypeV2, PostTypeV2, ...]
base_classes
Array<Symbol>
default:"[:Type, :Directive, :Schema]"
Base classes to include.
namespaces
Array<Symbol>
Namespaces to search. Defaults to all namespaces.
Get the list of all registered objects matching the criteria.

add_dependencies

type_map.add_dependencies(
  'app/graphql/types/user_type.rb',
  'app/graphql/types/post_type.rb',
  to: :v2
)
list
String | Array<String>
required
File paths or procs to load when the namespace is accessed.
to
Symbol
required
The namespace to associate dependencies with.
Add a list of dependencies to lazy load when the namespace is accessed.

postpone_registration

type_map.postpone_registration(UserType)
object
Class
required
The object to register later.
Mark the given object to be registered later when a fetch is triggered. Captures the caller location for error reporting.

associate

type_map.associate(:v2, GraphQL::V2)
namespace
Symbol
required
The namespace identifier.
mod
Module
required
The Ruby module to associate with the namespace.
Associate a Ruby module to a GraphQL namespace. If registered objects have no namespace, but their module_parents have been associated, the value is used.

associated_namespace_of

type_map.associated_namespace_of(GraphQL::V2::UserType)
# => :v2
object
Class
required
The object to find the associated namespace for.
Grab all the module_parents from the object and return the first matching associated namespace.

after_register

type_map.after_register('User', base_class: :Type) do |user_type|
  puts "User type registered: #{user_type.gql_name}"
end
name_or_key
String | Symbol
required
The name or key to watch for registration.
base_class
Symbol
default:":Type"
The base class to watch.
namespace
Symbol | Array<Symbol>
Namespace(s) to watch.
Add a callback that triggers when a type is registered under the given settings. If the item already exists, the callback is called immediately.

Usage Example

# Access the global type map
type_map = Rails::GraphQL.type_map

# Register a type
type_map.register(UserType)

# Fetch a type
user_type = type_map.fetch('User', base_class: :Type)

# Check existence
if type_map.exist?('CustomScalar', base_class: :Type)
  # ...
end

# Iterate over all types in a namespace
type_map.each_from(:v2, base_class: :Type) do |type|
  puts type.gql_name
end

# Get all objects
all_types = type_map.objects(base_classes: [:Type])

Build docs developers (and LLMs) love