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/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/catchall_middleware.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, Schema#query, Schema#mutation and Schema#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: CatchallMiddleware, Loader, Printer, ReduceTypes, TypeExpression Classes: InvalidTypeError, MiddlewareChain, PossibleTypes, RescueMiddleware, TimeoutMiddleware, TypeMap, Validation

Constant Summary collapse

DIRECTIVES =
[GraphQL::Directive::SkipDirective, GraphQL::Directive::IncludeDirective]
DYNAMIC_FIELDS =
["__type", "__typename", "__schema"]
RESOLVE_TYPE_PROC_REQUIRED =
-> (obj, ctx) { raise("Schema.resolve_type is undefined, can't resolve type for #{obj.inspect}") }

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Define::InstanceDefinable

#definition_proc=, included, #metadata

Constructor Details

#initialize(query: nil, mutation: nil, subscription: nil, max_depth: nil, max_complexity: nil, types: []) ⇒ Schema

Returns a new instance of Schema.

Parameters:

  • query (GraphQL::ObjectType) (defaults to: nil)

    the query root for the schema

  • mutation (GraphQL::ObjectType) (defaults to: nil)

    the mutation root for the schema

  • subscription (GraphQL::ObjectType) (defaults to: nil)

    the subscription root for the schema

  • max_depth (Integer) (defaults to: nil)

    maximum query nesting (if it’s greater, raise an error)

  • types (Array<GraphQL::BaseType>) (defaults to: [])

    additional types to include in this schema



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/graphql/schema.rb', line 92

def initialize(query: nil, mutation: nil, subscription: nil, max_depth: nil, max_complexity: nil, types: [])
  if query
    warn("Schema.new is deprecated, use Schema.define instead")
  end
  @query    = query
  @mutation = mutation
  @subscription = subscription
  @max_depth = max_depth
  @max_complexity = max_complexity
  @orphan_types = types
  @directives = DIRECTIVES.reduce({}) { |m, d| m[d.name] = d; m }
  @static_validator = GraphQL::StaticValidation::Validator.new(schema: self)
  @rescue_middleware = GraphQL::Schema::RescueMiddleware.new
  @middleware = [@rescue_middleware]
  @query_analyzers = []
  @resolve_type_proc = RESOLVE_TYPE_PROC_REQUIRED
  # 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 (readonly)

Returns the value of attribute directives.



68
69
70
# File 'lib/graphql/schema.rb', line 68

def directives
  @directives
end

#static_validatorObject (readonly)

Returns the value of attribute static_validator.



68
69
70
# File 'lib/graphql/schema.rb', line 68

def static_validator
  @static_validator
end

Instance Method Details

#execute(*args) ⇒ Hash

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

Returns:

  • (Hash)

    query result, ready to be serialized as JSON



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

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

#execution_strategy_for_operation(operation) ⇒ Object



186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/graphql/schema.rb', line 186

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) ⇒ Object

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



143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/graphql/schema.rb', line 143

def get_field(parent_type, field_name)
  ensure_defined
  defined_field = parent_type.get_field(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.types)
  else
    nil
  end
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



82
83
84
85
# File 'lib/graphql/schema.rb', line 82

def middleware
  ensure_defined
  @middleware
end

#node_identificationGraphQL::Relay::GlobalNodeIdentification

Returns the node identification instance for this schema, when using Relay.

Returns:



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

def node_identification
  ensure_defined
  @node_identification
end

#node_identification=(new_node_ident) ⇒ Object



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

def node_identification=(new_node_ident)
  new_node_ident.schema = self
  @node_identification = new_node_ident
end

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

TODO: when ‘resolve_type` is schema level, can this be removed?

Parameters:

Returns:



167
168
169
170
171
# File 'lib/graphql/schema.rb', line 167

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

#remove_handler(*args, &block) ⇒ Object



119
120
121
122
# File 'lib/graphql/schema.rb', line 119

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

#rescue_from(*args, &block) ⇒ Object



114
115
116
117
# File 'lib/graphql/schema.rb', line 114

def rescue_from(*args, &block)
  ensure_defined
  @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 (include Relay’s node interface)

Returns:



202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/graphql/schema.rb', line 202

def resolve_type(object, ctx)
  ensure_defined
  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



215
216
217
218
# File 'lib/graphql/schema.rb', line 215

def resolve_type=(new_resolve_type_proc)
  ensure_defined
  @resolve_type_proc = new_resolve_type_proc
end

#root_type_for_operation(operation) ⇒ Object



173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/graphql/schema.rb', line 173

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



159
160
161
162
# File 'lib/graphql/schema.rb', line 159

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

#typesGraphQL::Schema::TypeMap

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

Returns:



125
126
127
128
129
130
131
# File 'lib/graphql/schema.rb', line 125

def types
  @types ||= begin
    ensure_defined
    all_types = orphan_types + [query, mutation, subscription, GraphQL::Introspection::SchemaType]
    GraphQL::Schema::ReduceTypes.reduce(all_types.compact)
  end
end