Introspection
A GraphQL schema has a built-in introspection system that publishes the schema’s structure. In fact, the introspection system can be queried using GraphQL, for example:
{
__schema {
queryType {
name
}
}
}
# Returns:
# {
# "data": {
# "__schema": {
# "queryType": {
# "name": "Query"
# }
# }
# }
# }
This system is used for GraphQL tooling like the GraphiQL editor.
Here are the default parts of the introspection system:
-
__schemais a root-level field that contains data about the schema: its entry points, types, and directives. -
__type(name: String!)is a root-level field that returns data about a type with the givenname, if there is a type with that name. -
__typenameworks a bit differently: it can be added to any selection, and it will return the type of object being queried.
Here are some __typename examples:
{
user(id: "1") {
handle
__typename
}
}
# Returns:
# {
# "data": {
# "user": {
# "handle": "rmosolgo",
# "__typename": "User"
# }
# }
# }
For unions and interfaces, __typename returns the object type for the current object, for example:
{
search(term: "puppies") {
title
__typename
}
}
# Returns:
# {
# "data": {
# "search": [
# {
# "title": "Sound of Dogs Barking",
# "__typename": "AudioClip",
# },
# {
# "title": "Cute puppies playing with a stick",
# "__typename": "VideoClip",
# },
# {
# "title": "The names of my favorite pets",
# "__typename": "TextSnippet"
# },
# ]
# }
# }
Customizing Introspection
You can use custom introspection types.
# create a module namespace for your custom types: module Introspection # described below ... end class MySchema < GraphQL::Schema # ... # then pass the module as `introspection` introspection Introspection end
Keep in mind that off-the-shelf tooling may not support your custom introspection fields. You may have to modify existing tooling or create your own tools to make use of your extensions.
Introspection Namespace
The introspection namespace may contain a few different customizations:
-
Class-based object definitions which replace the built-in introspection types (such as
__Schemaand__Type) -
EntryPoints, A class-based object definition containing introspection entry points (like__schemaand__type(name:)). -
DynamicFields, A class-based object definition containing dynamic, globally-available fields (like__typename.)
Custom Introspection Types
The module passed as introspection may contain classes with the following names, which replace the built-in introspection types:
Custom class name | GraphQL type | Built-in class name –|–|– SchemaType | __Schema | GraphQL::Introspection::SchemaType TypeType | __Type | GraphQL::Introspection::TypeType DirectiveType | __Directive | GraphQL::Introspection::DirectiveType DirectiveLocationType | __DirectiveLocation | GraphQL::Introspection::DirectiveLocationEnum EnumValueType | __EnumValue | GraphQL::Introspection::EnumValueType FieldType | __Field | GraphQL::Introspection::FieldType InputValueType | __InputValue | GraphQL::Introspection::InputValueType TypeKindType | __TypeKind | GraphQL::Introspection::TypeKindEnum
The class-based definitions’ names must match the names of the types they replace.
Extending a Built-in Type
The built-in classes listed above may be extended:
module Introspection class SchemaType < GraphQL::Introspection::SchemaType # ... end end
Inside the class definition, you may:
-
add new fields by calling
field(...)and providing implementations -
redefine field structure by calling
field(...) -
provide new field implementations by defining methods
-
provide new descriptions by calling
description(...)
Introspection Entry Points
The GraphQL spec describes two entry points to the introspection system:
-
__schemareturns data about the schema (as type__Schema) -
__type(name:)returns data about a type, if one is found by name (as type__Type)
You can re-implement these fields or create new ones by creating a custom EntryPoints class in your introspection namespace:
module Introspection class EntryPoints < GraphQL::Introspection::EntryPoints # ... end end
This class is an object type definition, so you can override existing fields or add new ones here. They’ll be available on the root query object, but ignored in introspection (just like __schema and __type).
Dynamic Fields
The GraphQL spec describes a field which may be added to any selection: __typename. It returns the name of the current GraphQL type.
You can add fields like this (or override __typename) by creating a custom DynamicFields definition:
module Introspection class DynamicFields < GraphQL::Introspection::DynamicFields # ... end end
Any fields defined there will be available in any selection, but ignored in introspection (just like __typename).
Disabling Introspection
In case you want to turn off introspection entry points __schema and __type (for instance in the production environment) you can use a #disable_introspection_entry_points shorthand method:
class MySchema < GraphQL::Schema disable_introspection_entry_points if Rails.env.production? end
Where disable_introspection_entry_points will disable both the __schema and __type introspection entry points, you can also individually disable the introspection entry points using the disable_schema_introspection_entry_point and disable_type_introspection_entry_point shorthand methods:
class MySchema < GraphQL::Schema disable_schema_introspection_entry_point disable_type_introspection_entry_point end