Module: GraphQL::Introspection

Defined in:
lib/graphql.rb

Overview

Types & Fields that support GraphQL introspection queries

Defined Under Namespace

Classes: SchemaField, TypeByNameField, TypenameField

Constant Summary collapse

TypeType =
GraphQL::ObjectType.new do |t, type, field|
  t.name "__Type"
  t.description "A type in the GraphQL schema"

  t.fields = {
    name:           field.build(type: !type.String, desc: "The name of this type"),
    kind:           GraphQL::Field.new { |f|
                      f.type GraphQL::Introspection::TypeKindEnum
                      f.description "The kind of this type"
                      f.resolve -> (target, a, c) { target.kind.name }
                    },
    description:    field.build(type: type.String, desc: "The description for this type"),
    fields:         GraphQL::Introspection::FieldsField,
    ofType:         GraphQL::Introspection::OfTypeField,
    inputFields:    GraphQL::Introspection::InputFieldsField,
    possibleTypes:  GraphQL::Introspection::PossibleTypesField,
    enumValues:     GraphQL::Introspection::EnumValuesField,
    interfaces:     GraphQL::Introspection::InterfacesField,
  }
end
FieldType =
GraphQL::ObjectType.new do |t, type, field|
  t.name "__Field"
  t.description "Field on a GraphQL type"
  t.fields({
    name:         field.build(type: !type.String, desc: "The name for accessing this field"),
    description:  field.build(type: !type.String, desc: "The description of this field"),
    type:         field.build(type: !GraphQL::Introspection::TypeType, desc: "The return type of this field"),
    isDeprecated: GraphQL::Field.new { |f|
      f.type !type.Boolean
      f.description "Is this field deprecated?"
      f.resolve -> (obj, a, c) { !!obj.deprecation_reason }
    },
    args:  GraphQL::Introspection::ArgumentsField,
    deprecationReason: field.build(type: type.String, property: :deprecation_reason, desc: "Why this field was deprecated"),
  })
end
SchemaType =
GraphQL::ObjectType.new do |t, type|
  t.name "__Schema"
  t.description "A GraphQL schema"
  t.fields({
    types: GraphQL::Field.new { |f|
      f.type !type[!GraphQL::Introspection::TypeType]
      f.description "Types in this schema"
      f.resolve -> (obj, arg, ctx) { obj.types.values }
    },
    directives: GraphQL::Field.new { |f|
      f.type !type[!GraphQL::Introspection::DirectiveType]
      f.description "Directives in this schema"
      f.resolve -> (obj, arg, ctx) { obj.directives.values }
    },
    queryType: GraphQL::Field.new { |f|
      f.type !GraphQL::Introspection::TypeType
      f.description "The query root of this schema"
      f.resolve -> (obj, arg, ctx) { obj.query }
    },
    mutationType: GraphQL::Field.new { |f|
      f.type GraphQL::Introspection::TypeType
      f.description "The mutation root of this schema"
      f.resolve -> (obj, arg, ctx) { obj.mutation }
    },
  })
end
FieldsField =
GraphQL::Field.new do |f, type, field, arg|
  f.description "List of fields on this object"
  f.type -> { type[!GraphQL::Introspection::FieldType] }
  f.arguments({
    includeDeprecated: arg.build({type: GraphQL::BOOLEAN_TYPE, default_value: false})
  })
  f.resolve -> (object, arguments, context) {
    return nil if !object.kind.fields?
    fields = object.fields.values
    if !arguments["includeDeprecated"]
      fields = fields.select {|f| !f.deprecation_reason }
    end
    fields
  }
end
OfTypeField =
GraphQL::Field.new do |f|
  f.name "ofType"
  f.description "The modified type of this type"
  f.type -> { GraphQL::Introspection::TypeType }
  f.resolve -> (obj, args, ctx) { obj.kind.wraps? ? obj.of_type : nil }
end
DirectiveType =
GraphQL::ObjectType.new do |t, type, field|
  t.name "__Directive"
  t.description "A query directive in this schema"
  t.fields({
    name:         field.build(type: !type.String, desc: "The name of this directive"),
    description:  field.build(type: type.String, desc: "The description for this type"),
    args:         GraphQL::Introspection::ArgumentsField,
    onOperation:  field.build(type: !type.Boolean, property: :on_operation?, desc: "Does this directive apply to operations?"),
    onFragment:   field.build(type: !type.Boolean, property: :on_fragment?, desc: "Does this directive apply to fragments?"),
    onField:      field.build(type: !type.Boolean, property: :on_field?, desc: "Does this directive apply to fields?"),
  })
end
TypeKindEnum =
GraphQL::EnumType.new do |e|
  e.name "__TypeKind"
  e.description "The kinds of types in this GraphQL system"
  GraphQL::TypeKinds::KIND_NAMES.each do |kind_name|
    e.value(kind_name)
  end
end
ArgumentsField =
GraphQL::Field.new do |f|
  f.description "Arguments allowed to this object"
  f.type GraphQL::ListType.new(of_type: GraphQL::Introspection::InputValueType)
  f.resolve -> (target, a, c) { target.arguments.values }
end
EnumValueType =
GraphQL::ObjectType.new do |t, type, field|
  t.name "__EnumValue"
  t.description "A possible value for an Enum"
  t.fields({
    name:               field.build(type: !type.String),
    description:        field.build(type: !type.String),
    deprecationReason:  field.build(type: !type.String, property: :deprecation_reason),
    isDeprecated: GraphQL::Field.new { |f|
      f.type !type.Boolean
      f.resolve -> (obj, a, c) { !!obj.deprecation_reason }
    },
  })
end
InputValueType =
GraphQL::ObjectType.new do |t, type, field|
  t.name "__InputValue"
  t.description "An input for a field or InputObject"
  t.fields({
    name:         field.build(type: !type.String, desc: "The key for this value"),
    description:  field.build(type: type.String, desc: "What this value is used for"),
    type:         field.build(type: -> { GraphQL::Introspection::TypeType }, desc: "The expected type for this value"),
    defaultValue: field.build(type: type.String, property: :default_value, desc: "The value applied if no other value is provided")
  })
end
InterfacesField =
GraphQL::Field.new do |f, type|
  f.description "Interfaces which this object implements"
  f.type -> { !type[!GraphQL::Introspection::TypeType] }
  f.resolve -> (target, a, c) { target.kind.object? ? target.interfaces : nil }
end
EnumValuesField =
GraphQL::Field.new do |f, type, field, arg|
  f.description "Values for this enum"
  f.type type[!GraphQL::Introspection::EnumValueType]
  f.arguments({
    includeDeprecated: arg.build({type: GraphQL::BOOLEAN_TYPE, default_value: false})
  })
  f.resolve -> (object, arguments, context) {
    return nil if !object.kind.enum?
    fields = object.values.values
    if !arguments["includeDeprecated"]
      fields = fields.select {|f| !f.deprecation_reason }
    end
    fields
  }
end
InputFieldsField =
GraphQL::Field.new do |f, type|
  f.name "inputFields"
  f.description "fields on this input object"
  f.type type[GraphQL::Introspection::InputValueType]
  f.resolve -> (target, a, c) {
    if target.kind.input_object?
      target.input_fields.values
    else
      nil
    end
  }
end
INTROSPECTION_QUERY =

The introspection query to end all introspection queries, copied from github.com/graphql/graphql-js/blob/master/src/utilities/introspectionQuery.js

"
query IntrospectionQuery {
  __schema {
    queryType { name }
    mutationType { name }
    types {
      ...FullType
    }
    directives {
      name
      description
      args {
        ...InputValue
      }
      onOperation
      onFragment
      onField
    }
  }
}
fragment FullType on __Type {
  kind
  name
  description
  fields {
    name
    description
    args {
      ...InputValue
    }
    type {
      ...TypeRef
    }
    isDeprecated
    deprecationReason
  }
  inputFields {
    ...InputValue
  }
  interfaces {
    ...TypeRef
  }
  enumValues {
    name
    description
    isDeprecated
    deprecationReason
  }
  possibleTypes {
    ...TypeRef
  }
}
fragment InputValue on __InputValue {
  name
  description
  type { ...TypeRef }
  defaultValue
}
fragment TypeRef on __Type {
  kind
  name
  ofType {
    kind
    name
    ofType {
      kind
      name
      ofType {
        kind
        name
      }
    }
  }
}
"
PossibleTypesField =
GraphQL::Field.new do |f, type|
  f.description "Types which compose this Union or Interface"
  f.type -> { type[GraphQL::Introspection::TypeType] }
  f.resolve -> (target, a, c) { target.kind.resolves? ? target.possible_types : nil }
end