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:
__schema
is 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 given name
, if there is a type with that name.__typename
works 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"
# },
# ]
# }
# }
This is an experimental feature, only supported in class-based schemas.
With a class-based schema, 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.
The introspection namespace may contain a few different customizations:
EntryPoints
, A class-based object definition%20containing%20introspection%20entry%20points%20(like%20%60__schema%60%20and%20%60__type(name:)%60).DynamicFields
, A class-based object definition%20containing%20dynamic,%20globally-available%20fields%20(like%20%60__typename%60.)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.
The built-in classes listed above may be extended:
module Introspection
class SchemaType < GraphQL::Introspection::SchemaType
# ...
end
end
Inside the class definition, you may:
field(...)
and providing implementationsfield(...)
description(...)
The GraphQL spec describes two entry points to the introspection system:
__schema
returns 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 an object type definition, so you can override fields or add new ones here. They’ll be available on the root query
object, but ignored in introspection (just like __schema
and __type
).
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
defintion:
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
).
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