Module: GraphQL::Introspection

Defined in:
lib/graphql/introspection.rb,
lib/graphql/introspection/schema_field.rb,
lib/graphql/introspection/typename_field.rb,
lib/graphql/introspection/type_by_name_field.rb

Constant Summary collapse

TypeType =
GraphQL::ObjectType.define do
  name "__Type"
  description "The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in "\
              "GraphQL as represented by the `__TypeKind` enum.\n\n"\
              "Depending on the kind of a type, certain fields describe information about that type. "\
              "Scalar types provide no information beyond a name and description, while "\
              "Enum types provide their values. Object and Interface types provide the fields "\
              "they describe. Abstract types, Union and Interface, provide the Object types "\
              "possible at runtime. List and NonNull types compose other types."

  field :kind do
    type !GraphQL::Introspection::TypeKindEnum
    resolve ->(target, a, c) { target.kind.name }
  end

  field :name, types.String
  field :description, types.String
  field :fields,        GraphQL::Introspection::FieldsField
  field :interfaces,    GraphQL::Introspection::InterfacesField
  field :possibleTypes, GraphQL::Introspection::PossibleTypesField
  field :enumValues,    GraphQL::Introspection::EnumValuesField
  field :inputFields,   GraphQL::Introspection::InputFieldsField
  field :ofType,        GraphQL::Introspection::OfTypeField
  introspection true
end
FieldType =
GraphQL::ObjectType.define do
  name "__Field"
  description "Object and Interface types are described by a list of Fields, each of which has "\
              "a name, potentially a list of arguments, and a return type."
  field :name, !types.String
  field :description, types.String
  field :args, GraphQL::Introspection::ArgumentsField
  field :type, !GraphQL::Introspection::TypeType
  field :isDeprecated, !types.Boolean do
    resolve ->(obj, a, c) { !!obj.deprecation_reason }
  end
  field :deprecationReason, types.String, property: :deprecation_reason
  introspection true
end
SchemaType =
GraphQL::ObjectType.define do
  name "__Schema"
  description "A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all "\
              "available types and directives on the server, as well as the entry points for "\
              "query, mutation, and subscription operations."

  field :types, !types[!GraphQL::Introspection::TypeType], "A list of all types supported by this server." do
    resolve ->(obj, arg, ctx) { ctx.warden.types }
  end

  field :queryType, !GraphQL::Introspection::TypeType, "The type that query operations will be rooted at." do
    resolve ->(obj, arg, ctx) { ctx.warden.root_type_for_operation("query") }
  end

  field :mutationType, GraphQL::Introspection::TypeType, "If this server supports mutation, the type that mutation operations will be rooted at." do
    resolve ->(obj, arg, ctx) { ctx.warden.root_type_for_operation("mutation") }
  end

  field :subscriptionType, GraphQL::Introspection::TypeType, "If this server support subscription, the type that subscription operations will be rooted at." do
    resolve ->(obj, arg, ctx) { ctx.warden.root_type_for_operation("subscription") }
  end

  field :directives, !types[!GraphQL::Introspection::DirectiveType], "A list of all directives supported by this server." do
    resolve ->(obj, arg, ctx) { obj.directives.values }
  end

  introspection true
end
FieldsField =
GraphQL::Field.define do
  type -> { types[!GraphQL::Introspection::FieldType] }
  introspection true
  argument :includeDeprecated, GraphQL::BOOLEAN_TYPE, default_value: false
  resolve ->(object, arguments, context) {
    return nil if !object.kind.fields?
    fields = context.warden.fields(object)
    if !arguments["includeDeprecated"]
      fields = fields.select {|f| !f.deprecation_reason }
    end
    fields.sort_by(&:name)
  }
end
SchemaField =
GraphQL::Field.define do
  name("__schema")
  description("This GraphQL schema")
  introspection true
  type(!GraphQL::Introspection::SchemaType)
  resolve ->(o, a, ctx) { ctx.query.schema }
end
OfTypeField =
GraphQL::Field.define do
  name "ofType"
  introspection true
  type -> { GraphQL::Introspection::TypeType }
  resolve ->(obj, args, ctx) { obj.kind.wraps? ? obj.of_type : nil }
end
DirectiveType =
GraphQL::ObjectType.define do
  name "__Directive"
  description "A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document."\
              "\n\n"\
              "In some cases, you need to provide options to alter GraphQL's execution behavior "\
              "in ways field arguments will not suffice, such as conditionally including or "\
              "skipping a field. Directives provide this by describing additional information "\
              "to the executor."
  field :name, !types.String
  field :description, types.String
  field :locations, !types[!GraphQL::Introspection::DirectiveLocationEnum]
  field :args, field: GraphQL::Introspection::ArgumentsField
  field :onOperation, !types.Boolean, deprecation_reason: "Use `locations`.", property: :on_operation?
  field :onFragment, !types.Boolean, deprecation_reason: "Use `locations`.", property: :on_fragment?
  field :onField, !types.Boolean, deprecation_reason: "Use `locations`.", property: :on_field?
  introspection true
end
TypeKindEnum =
GraphQL::EnumType.define do
  name "__TypeKind"
  description "An enum describing what kind of type a given `__Type` is."
  GraphQL::TypeKinds::TYPE_KINDS.each do |type_kind|
    value(type_kind.name, type_kind.description)
  end
  introspection true
end
TypenameField =
GraphQL::Field.define do
  name "__typename"
  description "The name of this type"
  type -> { !GraphQL::STRING_TYPE }
  introspection true
  resolve ->(obj, a, ctx) { ctx.irep_node.owner_type }
end
ArgumentsField =
GraphQL::Field.define do
  type !GraphQL::ListType.new(of_type: !GraphQL::Introspection::InputValueType)
  introspection true
  resolve ->(obj, args, ctx) {
    ctx.warden.arguments(obj)
  }
end
EnumValueType =
GraphQL::ObjectType.define do
  name "__EnumValue"
  description "One possible value for a given Enum. Enum values are unique values, not a "\
              "placeholder for a string or numeric value. However an Enum value is returned in "\
              "a JSON response as a string."
  field :name, !types.String
  field :description, types.String
  field :isDeprecated, !types.Boolean do
    resolve ->(obj, a, c) { !!obj.deprecation_reason }
  end
  field :deprecationReason, types.String, property: :deprecation_reason
  introspection true
end
InputValueType =
GraphQL::ObjectType.define do
  name "__InputValue"
  description "Arguments provided to Fields or Directives and the input fields of an "\
              "InputObject are represented as Input Values which describe their type and "\
              "optionally a default value."
  field :name, !types.String
  field :description, types.String
  field :type, !GraphQL::Introspection::TypeType
  field :defaultValue, types.String, "A GraphQL-formatted string representing the default value for this input value." do
    resolve ->(obj, args, ctx) {
      if obj.default_value?
        value = obj.default_value
        if value.nil?
          'null'
        else
          coerced_default_value = obj.type.coerce_result(value, ctx)
          if obj.type.unwrap.is_a?(GraphQL::EnumType)
            coerced_default_value
          else
            GraphQL::Language.serialize(coerced_default_value)
          end
        end
      else
        nil
      end
    }
  end
  introspection true
end
InterfacesField =
GraphQL::Field.define do
  type -> { types[!GraphQL::Introspection::TypeType] }
  introspection true
  resolve ->(target, a, ctx) {
    if target.kind == GraphQL::TypeKinds::OBJECT
      ctx.warden.interfaces(target)
    else
      nil
    end
  }
end
EnumValuesField =
GraphQL::Field.define do
  type types[!GraphQL::Introspection::EnumValueType]
  introspection true
  argument :includeDeprecated, types.Boolean, default_value: false
  resolve ->(object, arguments, context) do
    if !object.kind.enum?
      nil
    else
      enum_values = context.warden.enum_values(object)

      if !arguments["includeDeprecated"]
        enum_values = enum_values.select {|f| !f.deprecation_reason }
      end

      enum_values
    end
  end
end
InputFieldsField =
GraphQL::Field.define do
  name "inputFields"
  introspection true
  type types[!GraphQL::Introspection::InputValueType]
  resolve ->(target, a, ctx) {
    if target.kind.input_object?
      ctx.warden.arguments(target)
    else
      nil
    end
  }
end
TypeByNameField =
GraphQL::Field.define do
  name("__type")
  description("A type in the GraphQL system")
  type(GraphQL::Introspection::TypeType)
  introspection true
  argument :name, !types.String
  resolve ->(o, args, ctx) {
    ctx.warden.get_type(args["name"])
  }
end
INTROSPECTION_QUERY =

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

"
query IntrospectionQuery {
  __schema {
    queryType { name }
    mutationType { name }
    subscriptionType { name }
    types {
      ...FullType
    }
    directives {
      name
      description
      locations
      args {
        ...InputValue
      }
    }
  }
}
fragment FullType on __Type {
  kind
  name
  description
  fields(includeDeprecated: true) {
    name
    description
    args {
      ...InputValue
    }
    type {
      ...TypeRef
    }
    isDeprecated
    deprecationReason
  }
  inputFields {
    ...InputValue
  }
  interfaces {
    ...TypeRef
  }
  enumValues(includeDeprecated: true) {
    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
        ofType {
          kind
          name
          ofType {
            kind
            name
            ofType {
              kind
              name
              ofType {
                kind
                name
              }
            }
          }
        }
      }
    }
  }
}
"
PossibleTypesField =
GraphQL::Field.define do
  type -> { types[!GraphQL::Introspection::TypeType] }
  introspection true
  resolve ->(target, args, ctx) {
    if target.kind.resolves?
      ctx.warden.possible_types(target)
    else
      nil
    end
  }
end
DirectiveLocationEnum =
GraphQL::EnumType.define do
  name "__DirectiveLocation"
  description "A Directive can be adjacent to many parts of the GraphQL language, a "\
              "__DirectiveLocation describes one such possible adjacencies."

  GraphQL::Directive::LOCATIONS.each do |location|
    value(location.to_s, GraphQL::Directive::LOCATION_DESCRIPTIONS[location], value: location)
  end
  introspection true
end