The Type Map is the central index for all GraphQL components in your application. It tracks types, directives, and schemas, ensuring they’re properly accessible from their requested scope. The Type Map also provides versioning for cache invalidation.
Inspired by ActiveRecord::Type::TypeMap, the Type Map uses a three-tier index: namespace → base_class → key.
When fetching from the Type Map, pending objects are registered:
# From lib/rails/graphql/type_map.rbdef register(object) namespaces = sanitize_namespaces(namespaces: object.namespaces, exclusive: true) namespaces << :base if namespaces.empty? base_class = find_base_class(object) ensure_base_class!(base_class) # Cache the name, key, and alias proc object_base = namespaces.first object_name = object.gql_name object_key = object.to_sym alias_proc = -> do value = dig(object_base, base_class, object_key) value.is_a?(Proc) ? value.call : value end # Register main type object for both key and name add(object_base, base_class, object_key, object) add(object_base, base_class, object_name, alias_proc) # Register all aliases aliases = object.try(:aliases) aliases&.each do |alias_name| add(object_base, base_class, alias_name, alias_proc) end # Register in remaining namespaces if namespaces.size > 1 keys_and_names = [object_key, object_name, *aliases] namespaces.drop(1).product(keys_and_names) do |(namespace, key_or_name)| add(namespace, base_class, key_or_name, alias_proc) end end @objects += 1 objectend
# Returns nil if not foundRails::GraphQL.type_map.fetch(:string)# => Rails::GraphQL::Type::Scalar::StringScalarRails::GraphQL.type_map.fetch(:unknown)# => nil
Rails::GraphQL.type_map.after_register(:custom_type) do |type| puts "Custom type registered: #{type.name}"end# Later, when registeredclass CustomType < GraphQL::Type::Objectend# Output: Custom type registered: CustomType
Callbacks are useful for conditionally adding fields to types that may not exist yet.
def add_dependencies(*list, to:) @dependencies[to].concat(list.flatten.compact)enddef load_dependencies!(**xargs) sanitize_namespaces(**xargs).reduce(false) do |result, namespace| next result if (list = @dependencies[namespace]).empty? while (src = list.shift) src.is_a?(Proc) ? src.call : require(src) end true endend