Class: GraphQL::Schema

Inherits:
Object
  • Object
show all
Includes:
Define::InstanceDefinable
Defined in:
lib/graphql/schema.rb,
lib/graphql/schema/loader.rb,
lib/graphql/schema/warden.rb,
lib/graphql/schema/printer.rb,
lib/graphql/schema/type_map.rb,
lib/graphql/schema/validation.rb,
lib/graphql/schema/reduce_types.rb,
lib/graphql/schema/possible_types.rb,
lib/graphql/schema/type_expression.rb,
lib/graphql/schema/middleware_chain.rb,
lib/graphql/schema/rescue_middleware.rb,
lib/graphql/schema/invalid_type_error.rb,
lib/graphql/schema/timeout_middleware.rb,
lib/graphql/schema/unique_within_type.rb,
lib/graphql/schema/catchall_middleware.rb,
lib/graphql/schema/build_from_definition.rb,
lib/graphql/schema/instrumented_field_map.rb

Overview

A GraphQL schema which may be queried with Query.

The Schema contains:

  • types for exposing your application
  • query analyzers for assessing incoming queries (including max depth & max complexity restrictions)
  • execution strategies for running incoming queries
  • middleware for interacting with execution

Schemas start with root types, #query, #mutation and #subscription. The schema will traverse the tree of fields & types, using those as starting points. Any undiscoverable types may be provided with the types configuration.

Schemas can restrict large incoming queries with max_depth and max_complexity configurations. (These configurations can be overridden by specific calls to #execute)

Schemas can specify how queries should be executed against them. query_execution_strategy, mutation_execution_strategy and subscription_execution_strategy each apply to corresponding root types.

A schema accepts a Relay::GlobalNodeIdentification instance for use with Relay IDs.

Examples:

defining a schema

MySchema = GraphQL::Schema.define do
  query QueryType
  middleware PermissionMiddleware
  rescue_from(ActiveRecord::RecordNotFound) { "Not found" }
  # If types are only connected by way of interfaces, they must be added here
  orphan_types ImageType, AudioType
end

Defined Under Namespace

Modules: BuildFromDefinition, CatchallMiddleware, Loader, Printer, ReduceTypes, TypeExpression, UniqueWithinType Classes: InstrumentedFieldMap, InvalidDocumentError, InvalidTypeError, MiddlewareChain, PossibleTypes, RescueMiddleware, TimeoutMiddleware, TypeMap, Validation, Warden

Constant Summary collapse

BUILT_IN_TYPES =
Hash[[INT_TYPE, STRING_TYPE, FLOAT_TYPE, BOOLEAN_TYPE, ID_TYPE].map{ |type| [type.name, type] }]
DIRECTIVES =
[GraphQL::Directive::IncludeDirective, GraphQL::Directive::SkipDirective, GraphQL::Directive::DeprecatedDirective]
DYNAMIC_FIELDS =
["__type", "__typename", "__schema"]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Define::InstanceDefinable

#metadata, #redefine

Constructor Details

#initializeSchema

Returns a new instance of Schema

Parameters:


83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/graphql/schema.rb', line 83

def initialize
  @orphan_types = []
  @directives = DIRECTIVES.reduce({}) { |m, d| m[d.name] = d; m }
  @static_validator = GraphQL::StaticValidation::Validator.new(schema: self)
  @middleware = []
  @query_analyzers = []
  @resolve_type_proc = nil
  @object_from_id_proc = nil
  @id_from_object_proc = nil
  @instrumenters = Hash.new { |h, k| h[k] = [] }
  # Default to the built-in execution strategy:
  @query_execution_strategy = GraphQL::Query::SerialExecution
  @mutation_execution_strategy = GraphQL::Query::SerialExecution
  @subscription_execution_strategy = GraphQL::Query::SerialExecution
end

Instance Attribute Details

#directivesObject

Returns the value of attribute directives


62
63
64
# File 'lib/graphql/schema.rb', line 62

def directives
  @directives
end

#id_from_object_procObject (readonly)

Returns the value of attribute id_from_object_proc


73
74
75
# File 'lib/graphql/schema.rb', line 73

def id_from_object_proc
  @id_from_object_proc
end

#instrumentersObject

Returns the value of attribute instrumenters


62
63
64
# File 'lib/graphql/schema.rb', line 62

def instrumenters
  @instrumenters
end

#max_complexityObject

Returns the value of attribute max_complexity


62
63
64
# File 'lib/graphql/schema.rb', line 62

def max_complexity
  @max_complexity
end

#max_depthObject

Returns the value of attribute max_depth


62
63
64
# File 'lib/graphql/schema.rb', line 62

def max_depth
  @max_depth
end

#middlewareArray<#call>

Returns Middlewares suitable for MiddlewareChain, applied to fields during execution

Returns:

  • (Array<#call>)

    Middlewares suitable for MiddlewareChain, applied to fields during execution


75
76
77
# File 'lib/graphql/schema.rb', line 75

def middleware
  @middleware
end

#mutationObject

Returns the value of attribute mutation


62
63
64
# File 'lib/graphql/schema.rb', line 62

def mutation
  @mutation
end

#mutation_execution_strategyObject

Returns the value of attribute mutation_execution_strategy


62
63
64
# File 'lib/graphql/schema.rb', line 62

def mutation_execution_strategy
  @mutation_execution_strategy
end

#object_from_id_procObject (readonly)

Returns the value of attribute object_from_id_proc


73
74
75
# File 'lib/graphql/schema.rb', line 73

def object_from_id_proc
  @object_from_id_proc
end

#orphan_typesObject

Returns the value of attribute orphan_types


62
63
64
# File 'lib/graphql/schema.rb', line 62

def orphan_types
  @orphan_types
end

#queryObject

Returns the value of attribute query


62
63
64
# File 'lib/graphql/schema.rb', line 62

def query
  @query
end

#query_analyzersObject

Returns the value of attribute query_analyzers


62
63
64
# File 'lib/graphql/schema.rb', line 62

def query_analyzers
  @query_analyzers
end

#query_execution_strategyObject

Returns the value of attribute query_execution_strategy


62
63
64
# File 'lib/graphql/schema.rb', line 62

def query_execution_strategy
  @query_execution_strategy
end

#resolve_type_procObject (readonly)

Returns the value of attribute resolve_type_proc


73
74
75
# File 'lib/graphql/schema.rb', line 73

def resolve_type_proc
  @resolve_type_proc
end

#static_validatorObject (readonly)

Returns the value of attribute static_validator


73
74
75
# File 'lib/graphql/schema.rb', line 73

def static_validator
  @static_validator
end

#subscriptionObject

Returns the value of attribute subscription


62
63
64
# File 'lib/graphql/schema.rb', line 62

def subscription
  @subscription
end

#subscription_execution_strategyObject

Returns the value of attribute subscription_execution_strategy


62
63
64
# File 'lib/graphql/schema.rb', line 62

def subscription_execution_strategy
  @subscription_execution_strategy
end

#typesGraphQL::Schema::TypeMap (readonly)

Returns { name => type } pairs of types in this schema

Returns:

See Also:

  • Restricted access to members of a schema

136
137
138
# File 'lib/graphql/schema.rb', line 136

def types
  @types
end

Class Method Details

.from_definition(definition_string) ⇒ GraphQL::Schema

Create schema from an IDL schema.

Parameters:

  • definition_string

    String A schema definition string

Returns:


274
275
276
# File 'lib/graphql/schema.rb', line 274

def self.from_definition(definition_string)
  GraphQL::Schema::BuildFromDefinition.from_definition(definition_string)
end

.from_introspection(introspection_result) ⇒ GraphQL::Schema

Create schema with the result of an introspection query.

Parameters:

Returns:


267
268
269
# File 'lib/graphql/schema.rb', line 267

def self.from_introspection(introspection_result)
  GraphQL::Schema::Loader.load(introspection_result)
end

Instance Method Details

#define(**kwargs, &block) ⇒ Object


107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/graphql/schema.rb', line 107

def define(**kwargs, &block)
  super
  ensure_defined
  all_types = orphan_types + [query, mutation, subscription, GraphQL::Introspection::SchemaType]
  @types = GraphQL::Schema::ReduceTypes.reduce(all_types.compact)

  @instrumented_field_map = InstrumentedFieldMap.new(self)
  field_instrumenters = @instrumenters[:field]
  types.each do |type_name, type|
    if type.kind.fields?
      type.all_fields.each do |field_defn|

        instrumented_field_defn = field_instrumenters.reduce(field_defn) do |defn, inst|
          inst.instrument(type, defn)
        end

        @instrumented_field_map.set(type.name, field_defn.name, instrumented_field_defn)
      end
    end
  end
  # Assert that all necessary configs are present:
  validation_error = Validation.validate(self)
  validation_error && raise(NotImplementedError, validation_error)
  nil
end

#execute(*args) ⇒ Hash

Execute a query on itself. See Query#initialize for arguments.

Returns:

  • (Hash)

    query result, ready to be serialized as JSON


141
142
143
144
# File 'lib/graphql/schema.rb', line 141

def execute(*args)
  query_obj = GraphQL::Query.new(self, *args)
  query_obj.result
end

#execution_strategy_for_operation(operation) ⇒ Object


190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/graphql/schema.rb', line 190

def execution_strategy_for_operation(operation)
  case operation
  when "query"
    query_execution_strategy
  when "mutation"
    mutation_execution_strategy
  when "subscription"
    subscription_execution_strategy
  else
    raise ArgumentError, "unknown operation type: #{operation}"
  end
end

#get_field(parent_type, field_name) ⇒ GraphQL::Field?

Resolve field named field_name for type parent_type. Handles dynamic fields __typename, __type and __schema, too

Returns:

See Also:

  • Restricted access to members of a schema

150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/graphql/schema.rb', line 150

def get_field(parent_type, field_name)
  defined_field = @instrumented_field_map.get(parent_type.name, field_name)
  if defined_field
    defined_field
  elsif field_name == "__typename"
    GraphQL::Introspection::TypenameField.create(parent_type)
  elsif field_name == "__schema" && parent_type == query
    GraphQL::Introspection::SchemaField.create(self)
  elsif field_name == "__type" && parent_type == query
    GraphQL::Introspection::TypeByNameField.create(self)
  else
    nil
  end
end

#id_from_object(object, type, ctx) ⇒ String

Get a unique identifier from this object

Parameters:

Returns:

  • (String)

    a unique identifier for object which clients can use to refetch it


251
252
253
254
255
256
257
# File 'lib/graphql/schema.rb', line 251

def id_from_object(object, type, ctx)
  if @id_from_object_proc.nil?
    raise(NotImplementedError, "Can't generate an ID for #{object.inspect} of type #{type}, schema's `id_from_object` must be defined")
  else
    @id_from_object_proc.call(object, type, ctx)
  end
end

#id_from_object=(new_proc) ⇒ Object

Parameters:

  • new_proc (#call)

    A new callable for generating unique IDs


260
261
262
# File 'lib/graphql/schema.rb', line 260

def id_from_object=(new_proc)
  @id_from_object_proc = new_proc
end

#object_from_id(id, ctx) ⇒ Any

Fetch an application object by its unique id

Parameters:

  • id (String)

    A unique identifier, provided previously by this GraphQL schema

  • ctx (GraphQL::Query::Context)

    The context for the current query

Returns:

  • (Any)

    The application object identified by id


233
234
235
236
237
238
239
# File 'lib/graphql/schema.rb', line 233

def object_from_id(id, ctx)
  if @object_from_id_proc.nil?
    raise(NotImplementedError, "Can't fetch an object for id \"#{id}\" because the schema's `object_from_id (id, ctx) -> { ... }` function is not defined")
  else
    @object_from_id_proc.call(id, ctx)
  end
end

#object_from_id=(new_proc) ⇒ Object

Parameters:

  • new_proc (#call)

    A new callable for fetching objects by ID


242
243
244
# File 'lib/graphql/schema.rb', line 242

def object_from_id=(new_proc)
  @object_from_id_proc = new_proc
end

#possible_types(type_defn) ⇒ Array<GraphQL::ObjectType>

Returns types which belong to type_defn in this schema

Parameters:

Returns:

See Also:

  • Restricted access to members of a schema

172
173
174
175
# File 'lib/graphql/schema.rb', line 172

def possible_types(type_defn)
  @possible_types ||= GraphQL::Schema::PossibleTypes.new(self)
  @possible_types.possible_types(type_defn)
end

#remove_handler(*args, &block) ⇒ Object


103
104
105
# File 'lib/graphql/schema.rb', line 103

def remove_handler(*args, &block)
  rescue_middleware.remove_handler(*args, &block)
end

#rescue_from(*args, &block) ⇒ Object


99
100
101
# File 'lib/graphql/schema.rb', line 99

def rescue_from(*args, &block)
  rescue_middleware.rescue_from(*args, &block)
end

#resolve_type(object, ctx) ⇒ GraphQL::ObjectType

Determine the GraphQL type for a given object. This is required for unions and interfaces (including Relay's Node interface)

Parameters:

  • object (Any)

    An application object which GraphQL is currently resolving on

  • ctx (GraphQL::Query::Context)

    The context for the current query

Returns:

See Also:

  • Restricted access to members of a schema

209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/graphql/schema.rb', line 209

def resolve_type(object, ctx)
  if @resolve_type_proc.nil?
    raise(NotImplementedError, "Can't determine GraphQL type for: #{object.inspect}, define `resolve_type (obj, ctx) -> { ... }` inside `Schema.define`.")
  end

  type_result = @resolve_type_proc.call(object, ctx)
  if type_result.nil?
    nil
  elsif !type_result.is_a?(GraphQL::BaseType)
    type_str = "#{type_result} (#{type_result.class.name})"
    raise "resolve_type(#{object}) returned #{type_str}, but it should return a GraphQL type"
  else
    type_result
  end
end

#resolve_type=(new_resolve_type_proc) ⇒ Object


225
226
227
# File 'lib/graphql/schema.rb', line 225

def resolve_type=(new_resolve_type_proc)
  @resolve_type_proc = new_resolve_type_proc
end

#root_type_for_operation(operation) ⇒ Object


177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/graphql/schema.rb', line 177

def root_type_for_operation(operation)
  case operation
  when "query"
    query
  when "mutation"
    mutation
  when "subscription"
    subscription
  else
    raise ArgumentError, "unknown operation type: #{operation}"
  end
end

#type_from_ast(ast_node) ⇒ Object


165
166
167
# File 'lib/graphql/schema.rb', line 165

def type_from_ast(ast_node)
  GraphQL::Schema::TypeExpression.build_type(self.types, ast_node)
end