graphql 1.6.4 → 1.6.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/core.rb +47 -0
  3. data/lib/generators/graphql/install_generator.rb +15 -20
  4. data/lib/generators/graphql/mutation_generator.rb +31 -1
  5. data/lib/generators/graphql/templates/mutation.erb +2 -2
  6. data/lib/generators/graphql/templates/mutation_type.erb +5 -0
  7. data/lib/generators/graphql/templates/schema.erb +0 -1
  8. data/lib/graphql/argument.rb +6 -5
  9. data/lib/graphql/backwards_compatibility.rb +18 -4
  10. data/lib/graphql/base_type.rb +1 -1
  11. data/lib/graphql/compatibility/execution_specification/counter_schema.rb +1 -1
  12. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +1 -1
  13. data/lib/graphql/compatibility/lazy_execution_specification.rb +9 -2
  14. data/lib/graphql/define.rb +1 -0
  15. data/lib/graphql/define/defined_object_proxy.rb +1 -1
  16. data/lib/graphql/define/no_definition_error.rb +7 -0
  17. data/lib/graphql/enum_type.rb +4 -0
  18. data/lib/graphql/execution/execute.rb +3 -3
  19. data/lib/graphql/execution/field_result.rb +1 -1
  20. data/lib/graphql/execution/lazy/resolve.rb +10 -9
  21. data/lib/graphql/execution/multiplex.rb +6 -5
  22. data/lib/graphql/input_object_type.rb +5 -1
  23. data/lib/graphql/interface_type.rb +12 -3
  24. data/lib/graphql/query.rb +21 -5
  25. data/lib/graphql/query/context.rb +11 -0
  26. data/lib/graphql/schema.rb +48 -27
  27. data/lib/graphql/schema/build_from_definition.rb +1 -1
  28. data/lib/graphql/schema/build_from_definition/resolve_map.rb +2 -2
  29. data/lib/graphql/schema/loader.rb +1 -1
  30. data/lib/graphql/schema/traversal.rb +91 -0
  31. data/lib/graphql/schema/validation.rb +1 -1
  32. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +41 -7
  33. data/lib/graphql/union_type.rb +13 -2
  34. data/lib/graphql/version.rb +1 -1
  35. data/readme.md +1 -3
  36. data/spec/generators/graphql/install_generator_spec.rb +3 -1
  37. data/spec/generators/graphql/mutation_generator_spec.rb +14 -0
  38. data/spec/graphql/analysis/max_query_complexity_spec.rb +12 -1
  39. data/spec/graphql/analysis/query_complexity_spec.rb +1 -1
  40. data/spec/graphql/argument_spec.rb +29 -0
  41. data/spec/graphql/define/assign_argument_spec.rb +4 -4
  42. data/spec/graphql/define/instance_definable_spec.rb +1 -1
  43. data/spec/graphql/enum_type_spec.rb +8 -0
  44. data/spec/graphql/execution/lazy_spec.rb +30 -3
  45. data/spec/graphql/interface_type_spec.rb +44 -0
  46. data/spec/graphql/introspection/schema_type_spec.rb +3 -0
  47. data/spec/graphql/introspection/type_type_spec.rb +1 -0
  48. data/spec/graphql/object_type_spec.rb +8 -3
  49. data/spec/graphql/query/context_spec.rb +18 -0
  50. data/spec/graphql/query/executor_spec.rb +1 -1
  51. data/spec/graphql/query/literal_input_spec.rb +31 -15
  52. data/spec/graphql/query/serial_execution/value_resolution_spec.rb +1 -1
  53. data/spec/graphql/query/variables_spec.rb +25 -1
  54. data/spec/graphql/query_spec.rb +24 -9
  55. data/spec/graphql/relay/mutation_spec.rb +1 -1
  56. data/spec/graphql/schema/build_from_definition_spec.rb +1 -1
  57. data/spec/graphql/schema/loader_spec.rb +1 -1
  58. data/spec/graphql/schema/printer_spec.rb +1 -1
  59. data/spec/graphql/schema/{reduce_types_spec.rb → traversal_spec.rb} +21 -4
  60. data/spec/graphql/schema/warden_spec.rb +1 -1
  61. data/spec/graphql/schema_spec.rb +23 -2
  62. data/spec/graphql/static_validation/rules/variable_usages_are_allowed_spec.rb +133 -0
  63. data/spec/graphql/union_type_spec.rb +53 -0
  64. data/spec/spec_helper.rb +9 -0
  65. data/spec/support/dummy/data.rb +14 -5
  66. data/spec/support/dummy/schema.rb +46 -5
  67. data/spec/support/star_wars/data.rb +10 -6
  68. data/spec/support/star_wars/schema.rb +5 -2
  69. metadata +8 -7
  70. data/lib/graphql/schema/instrumented_field_map.rb +0 -40
  71. data/lib/graphql/schema/reduce_types.rb +0 -69
  72. data/lib/graphql/schema/type_map.rb +0 -31
@@ -35,17 +35,18 @@ module GraphQL
35
35
  end
36
36
 
37
37
  class << self
38
- def run_all(schema, query_options, *rest)
38
+ def run_all(schema, query_options, *args)
39
39
  queries = query_options.map { |opts| GraphQL::Query.new(schema, nil, opts) }
40
- run_queries(schema, queries, *rest)
40
+ run_queries(schema, queries, *args)
41
41
  end
42
42
 
43
43
  # @param schema [GraphQL::Schema]
44
44
  # @param queries [Array<GraphQL::Query>]
45
45
  # @param context [Hash]
46
- # @param max_complexity [Integer]
46
+ # @param max_complexity [Integer, nil]
47
47
  # @return [Array<Hash>] One result per query
48
- def run_queries(schema, queries, context: {}, max_complexity: nil)
48
+ def run_queries(schema, queries, context: {}, max_complexity: schema.max_complexity)
49
+
49
50
  if has_custom_strategy?(schema)
50
51
  if queries.length != 1
51
52
  raise ArgumentError, "Multiplexing doesn't support custom execution strategies, run one query at a time instead"
@@ -161,7 +162,7 @@ module GraphQL
161
162
  end
162
163
 
163
164
  multiplex_analyzers = schema.multiplex_analyzers
164
- if max_complexity ||= schema.max_complexity
165
+ if max_complexity
165
166
  multiplex_analyzers += [GraphQL::Analysis::MaxQueryComplexity.new(max_complexity)]
166
167
  end
167
168
 
@@ -105,6 +105,11 @@ module GraphQL
105
105
  warden = ctx.warden
106
106
  result = GraphQL::Query::InputValidationResult.new
107
107
 
108
+ if input.is_a?(Array)
109
+ result.add_problem(INVALID_OBJECT_MESSAGE % { object: JSON.generate(input, quirks_mode: true) })
110
+ return result
111
+ end
112
+
108
113
  # We're not actually _using_ the coerced result, we're just
109
114
  # using these methods to make sure that the object will
110
115
  # behave like a hash below, when we call `each` on it.
@@ -121,7 +126,6 @@ module GraphQL
121
126
  end
122
127
  end
123
128
 
124
-
125
129
  visible_arguments_map = warden.arguments(self).reduce({}) { |m, f| m[f.name] = f; m}
126
130
 
127
131
  # Items in the input that are unexpected
@@ -23,14 +23,15 @@ module GraphQL
23
23
  # end
24
24
  #
25
25
  class InterfaceType < GraphQL::BaseType
26
- accepts_definitions :fields, field: GraphQL::Define::AssignObjectField
26
+ accepts_definitions :fields, :resolve_type, field: GraphQL::Define::AssignObjectField
27
27
 
28
- attr_accessor :fields
29
- ensure_defined :fields
28
+ attr_accessor :fields, :resolve_type_proc
29
+ ensure_defined :fields, :resolve_type_proc, :resolve_type
30
30
 
31
31
  def initialize
32
32
  super
33
33
  @fields = {}
34
+ @resolve_type_proc = nil
34
35
  end
35
36
 
36
37
  def initialize_copy(other)
@@ -42,6 +43,14 @@ module GraphQL
42
43
  GraphQL::TypeKinds::INTERFACE
43
44
  end
44
45
 
46
+ def resolve_type(value, ctx)
47
+ ctx.query.resolve_type(self, value)
48
+ end
49
+
50
+ def resolve_type=(resolve_type_callable)
51
+ @resolve_type_proc = resolve_type_callable
52
+ end
53
+
45
54
  # @return [GraphQL::Field] The defined field for `field_name`
46
55
  def get_field(field_name)
47
56
  fields[field_name]
data/lib/graphql/query.rb CHANGED
@@ -27,7 +27,10 @@ module GraphQL
27
27
  end
28
28
  end
29
29
 
30
- attr_reader :schema, :context, :root_value, :warden, :provided_variables, :operation_name
30
+ attr_reader :schema, :context, :root_value, :warden, :provided_variables
31
+
32
+ # @return [nil, String] The operation name provided by client or the one inferred from the document. Used to determine which operation to run.
33
+ attr_accessor :operation_name
31
34
 
32
35
  # @return [Boolean] if false, static validation is skipped (execution behavior for invalid queries is undefined)
33
36
  attr_accessor :validate
@@ -74,7 +77,13 @@ module GraphQL
74
77
  @query_string = query_string || query
75
78
  @document = document
76
79
 
77
- @resolved_types_cache = Hash.new { |h, k| h[k] = @schema.resolve_type(k, @context) }
80
+ # A two-layer cache of type resolution:
81
+ # { abstract_type => { value => resolved_type } }
82
+ @resolved_types_cache = Hash.new do |h1, k1|
83
+ h1[k1] = Hash.new do |h2, k2|
84
+ h2[k2] = @schema.resolve_type(k1, k2, @context)
85
+ end
86
+ end
78
87
 
79
88
  @arguments_cache = ArgumentsCache.build(self)
80
89
 
@@ -184,11 +193,17 @@ module GraphQL
184
193
 
185
194
  def_delegators :warden, :get_type, :get_field, :possible_types, :root_type_for_operation
186
195
 
196
+ # @param abstract_type [GraphQL::UnionType, GraphQL::InterfaceType]
187
197
  # @param value [Object] Any runtime value
188
198
  # @return [GraphQL::ObjectType, nil] The runtime type of `value` from {Schema#resolve_type}
189
199
  # @see {#possible_types} to apply filtering from `only` / `except`
190
- def resolve_type(value)
191
- @resolved_types_cache[value]
200
+ def resolve_type(abstract_type, value = :__undefined__)
201
+ if value.is_a?(Symbol) && value == :__undefined__
202
+ # Old method signature
203
+ value = abstract_type
204
+ abstract_type = nil
205
+ end
206
+ @resolved_types_cache[abstract_type][value]
192
207
  end
193
208
 
194
209
  def mutation?
@@ -250,7 +265,8 @@ module GraphQL
250
265
  elsif parse_error
251
266
  # This will be handled later
252
267
  else
253
- raise ArgumentError, "a query string or document is required"
268
+ parse_error = GraphQL::ExecutionError.new("No query string was present")
269
+ @context.add_error(parse_error)
254
270
  end
255
271
 
256
272
  # Trying to execute a document
@@ -87,6 +87,17 @@ module GraphQL
87
87
  GraphQL::Execution::Execute::SKIP
88
88
  end
89
89
 
90
+ # Add error at query-level.
91
+ # @param error [GraphQL::ExecutionError] an execution error
92
+ # @return [void]
93
+ def add_error(error)
94
+ if !error.is_a?(ExecutionError)
95
+ raise TypeError, "expected error to be a ExecutionError, but was #{error.class}"
96
+ end
97
+ errors << error
98
+ nil
99
+ end
100
+
90
101
  class FieldResolutionContext
91
102
  extend GraphQL::Delegate
92
103
 
@@ -4,15 +4,13 @@ require "graphql/schema/catchall_middleware"
4
4
  require "graphql/schema/default_parse_error"
5
5
  require "graphql/schema/default_type_error"
6
6
  require "graphql/schema/invalid_type_error"
7
- require "graphql/schema/instrumented_field_map"
8
7
  require "graphql/schema/middleware_chain"
9
8
  require "graphql/schema/null_mask"
10
9
  require "graphql/schema/possible_types"
11
10
  require "graphql/schema/rescue_middleware"
12
- require "graphql/schema/reduce_types"
13
11
  require "graphql/schema/timeout_middleware"
12
+ require "graphql/schema/traversal"
14
13
  require "graphql/schema/type_expression"
15
- require "graphql/schema/type_map"
16
14
  require "graphql/schema/unique_within_type"
17
15
  require "graphql/schema/validation"
18
16
  require "graphql/schema/warden"
@@ -128,6 +126,7 @@ module GraphQL
128
126
  @mutation_execution_strategy = self.class.default_execution_strategy
129
127
  @subscription_execution_strategy = self.class.default_execution_strategy
130
128
  @default_mask = GraphQL::Schema::NullMask
129
+ @rebuilding_artifacts = false
131
130
  end
132
131
 
133
132
  def initialize_copy(other)
@@ -185,15 +184,15 @@ module GraphQL
185
184
  def define(**kwargs, &block)
186
185
  super
187
186
  ensure_defined
188
- build_types_map
189
187
  # Assert that all necessary configs are present:
190
188
  validation_error = Validation.validate(self)
191
189
  validation_error && raise(NotImplementedError, validation_error)
192
- build_instrumented_field_map
190
+ rebuild_artifacts
191
+
193
192
  @definition_error = nil
194
193
  nil
195
194
  rescue StandardError => err
196
- if @raise_definition_error
195
+ if @raise_definition_error || err.is_a?(CyclicalDefinitionError)
197
196
  raise
198
197
  else
199
198
  # Raise this error _later_ to avoid messing with Rails constant loading
@@ -209,14 +208,17 @@ module GraphQL
209
208
  def instrument(instrumentation_type, instrumenter)
210
209
  @instrumenters[instrumentation_type] << instrumenter
211
210
  if instrumentation_type == :field
212
- build_instrumented_field_map
211
+ rebuild_artifacts
213
212
  end
214
213
  end
215
214
 
216
215
  # @see [GraphQL::Schema::Warden] Restricted access to members of a schema
217
216
  # @return [GraphQL::Schema::TypeMap] `{ name => type }` pairs of types in this schema
218
217
  def types
219
- @types ||= build_types_map
218
+ @types ||= begin
219
+ rebuild_artifacts
220
+ @types
221
+ end
220
222
  end
221
223
 
222
224
  # Execute a query on itself. Raises an error if the schema definition is invalid.
@@ -226,7 +228,8 @@ module GraphQL
226
228
  if query_str
227
229
  kwargs[:query] = query_str
228
230
  end
229
- all_results = multiplex([kwargs])
231
+ # Since we're running one query, don't run a multiplex-level complexity analyzer
232
+ all_results = multiplex([kwargs], max_complexity: nil)
230
233
  all_results[0]
231
234
  end
232
235
 
@@ -248,9 +251,9 @@ module GraphQL
248
251
  # @param queries [Array<Hash>] Keyword arguments for each query
249
252
  # @param context [Hash] Multiplex-level context
250
253
  # @return [Array<Hash>] One result for each query in the input
251
- def multiplex(*args)
254
+ def multiplex(queries, **kwargs)
252
255
  with_definition_error_check {
253
- GraphQL::Execution::Multiplex.run_all(self, *args)
256
+ GraphQL::Execution::Multiplex.run_all(self, queries, **kwargs)
254
257
  }
255
258
  end
256
259
 
@@ -271,7 +274,7 @@ module GraphQL
271
274
  raise "Unexpected parent_type: #{parent_type}"
272
275
  end
273
276
 
274
- defined_field = @instrumented_field_map.get(parent_type_name, field_name)
277
+ defined_field = @instrumented_field_map[parent_type_name][field_name]
275
278
  if defined_field
276
279
  defined_field
277
280
  elsif field_name == "__typename"
@@ -289,7 +292,7 @@ module GraphQL
289
292
  # Fields for this type, after instrumentation is applied
290
293
  # @return [Hash<String, GraphQL::Field>]
291
294
  def get_fields(type)
292
- @instrumented_field_map.get_all(type.name)
295
+ @instrumented_field_map[type.name]
293
296
  end
294
297
 
295
298
  def type_from_ast(ast_node)
@@ -335,15 +338,29 @@ module GraphQL
335
338
  # Determine the GraphQL type for a given object.
336
339
  # This is required for unions and interfaces (including Relay's `Node` interface)
337
340
  # @see [GraphQL::Schema::Warden] Restricted access to members of a schema
341
+ # @param type [GraphQL::UnionType, GraphQL:InterfaceType] the abstract type which is being resolved
338
342
  # @param object [Any] An application object which GraphQL is currently resolving on
339
343
  # @param ctx [GraphQL::Query::Context] The context for the current query
340
344
  # @return [GraphQL::ObjectType] The type for exposing `object` in GraphQL
341
- def resolve_type(object, ctx)
342
- if @resolve_type_proc.nil?
343
- raise(NotImplementedError, "Can't determine GraphQL type for: #{object.inspect}, define `resolve_type (obj, ctx) -> { ... }` inside `Schema.define`.")
345
+ def resolve_type(type, object, ctx = :__undefined__)
346
+ if ctx == :__undefined__
347
+ # Old method signature
348
+ ctx = object
349
+ object = type
350
+ type = nil
351
+ end
352
+
353
+ # Prefer a type-local function; fall back to the schema-level function
354
+ type_proc = type && type.resolve_type_proc
355
+ type_result = if type_proc
356
+ type_proc.call(object, ctx)
357
+ else
358
+ if @resolve_type_proc.nil?
359
+ raise(NotImplementedError, "Can't determine GraphQL type for: #{object.inspect}, define `resolve_type (obj, ctx) -> { ... }` inside `Schema.define`.")
360
+ end
361
+ @resolve_type_proc.call(type, object, ctx)
344
362
  end
345
363
 
346
- type_result = @resolve_type_proc.call(object, ctx)
347
364
  if type_result.nil?
348
365
  nil
349
366
  elsif !type_result.is_a?(GraphQL::BaseType)
@@ -355,7 +372,8 @@ module GraphQL
355
372
  end
356
373
 
357
374
  def resolve_type=(new_resolve_type_proc)
358
- @resolve_type_proc = new_resolve_type_proc
375
+ callable = GraphQL::BackwardsCompatibility.wrap_arity(new_resolve_type_proc, from: 2, to: 3, last: true, name: "Schema#resolve_type(type, obj, ctx)")
376
+ @resolve_type_proc = callable
359
377
  end
360
378
 
361
379
  # Fetch an application object by its unique id
@@ -513,17 +531,20 @@ module GraphQL
513
531
  GraphQL::Relay::Mutation::Instrumentation,
514
532
  ]
515
533
 
516
- # Apply instrumentation to fields. Relay instrumentation is applied last
517
- # so that user-provided instrumentation can wrap user-provided resolve functions,
518
- # _then_ Relay helpers can wrap the returned objects.
519
- def build_instrumented_field_map
520
- all_instrumenters = @instrumenters[:field] + BUILT_IN_INSTRUMENTERS + @instrumenters[:field_after_built_ins]
521
- @instrumented_field_map = InstrumentedFieldMap.new(self, all_instrumenters)
534
+ def rebuild_artifacts
535
+ if @rebuilding_artifacts
536
+ raise CyclicalDefinitionError, "Part of the schema build process re-triggered the schema build process, causing an infinite loop. Avoid using Schema#types, Schema#possible_types, and Schema#get_field during schema build."
537
+ else
538
+ @rebuilding_artifacts = true
539
+ traversal = Traversal.new(self)
540
+ @types = traversal.type_map
541
+ @instrumented_field_map = traversal.instrumented_field_map
542
+ end
543
+ ensure
544
+ @rebuilding_artifacts = false
522
545
  end
523
546
 
524
- def build_types_map
525
- all_types = orphan_types + [query, mutation, subscription, GraphQL::Introspection::SchemaType]
526
- @types = GraphQL::Schema::ReduceTypes.reduce(all_types.compact)
547
+ class CyclicalDefinitionError < GraphQL::Error
527
548
  end
528
549
 
529
550
  def with_definition_error_check
@@ -110,7 +110,7 @@ module GraphQL
110
110
  schema
111
111
  end
112
112
 
113
- NullResolveType = ->(obj, ctx) {
113
+ NullResolveType = ->(type, obj, ctx) {
114
114
  raise(NotImplementedError, "Generated Schema cannot use Interface or Union types for execution.")
115
115
  }
116
116
 
@@ -46,8 +46,8 @@ module GraphQL
46
46
 
47
47
  # Check the normalized hash, not the user input:
48
48
  if @resolve_hash.key?("resolve_type")
49
- define_singleton_method :resolve_type do |type, ctx|
50
- @resolve_hash.fetch("resolve_type").call(type, ctx)
49
+ define_singleton_method :resolve_type do |type, obj, ctx|
50
+ @resolve_hash.fetch("resolve_type").call(type, obj, ctx)
51
51
  end
52
52
  end
53
53
  end
@@ -33,7 +33,7 @@ module GraphQL
33
33
  Schema.define(**kargs, raise_definition_error: true)
34
34
  end
35
35
 
36
- NullResolveType = ->(obj, ctx) {
36
+ NullResolveType = ->(type, obj, ctx) {
37
37
  raise(NotImplementedError, "This schema was loaded from string, so it can't resolve types for objects")
38
38
  }
39
39
 
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ class Schema
4
+ # Visit the members of this schema and build up artifacts for runtime.
5
+ # @api private
6
+ class Traversal
7
+ # @return [Hash<String => GraphQL::BaseType]
8
+ attr_reader :type_map
9
+
10
+ # @return [Hash<String => Hash<String => GraphQL::Field>>]
11
+ attr_reader :instrumented_field_map
12
+
13
+ # @param schema [GraphQL::Schema]
14
+ def initialize(schema, introspection: true)
15
+ @schema = schema
16
+ @introspection = introspection
17
+ @field_instrumenters =
18
+ schema.instrumenters[:field] +
19
+ Schema::BUILT_IN_INSTRUMENTERS +
20
+ schema.instrumenters[:field_after_built_ins]
21
+
22
+ @type_map = {}
23
+ @instrumented_field_map = Hash.new { |h, k| h[k] = {} }
24
+ visit(schema, nil)
25
+ end
26
+
27
+ private
28
+
29
+ def visit(member, context_description)
30
+ case member
31
+ when GraphQL::Schema
32
+ # Find the starting points, then visit them
33
+ visit_roots = [member.query, member.mutation, member.subscription]
34
+ if @introspection
35
+ visit_roots << GraphQL::Introspection::SchemaType
36
+ end
37
+ visit_roots.concat(member.orphan_types)
38
+ visit_roots.compact!
39
+ visit_roots.each { |t| visit(t, t.name) }
40
+ when GraphQL::BaseType
41
+ type_defn = member.unwrap
42
+ prev_type = @type_map[type_defn.name]
43
+ # Continue to visit this type if it's the first time we've seen it:
44
+ if prev_type.nil?
45
+ validate_type(type_defn, context_description)
46
+ @type_map[type_defn.name] = type_defn
47
+ case type_defn
48
+ when GraphQL::ObjectType
49
+ type_defn.interfaces.each { |i| visit(i, "Interface on #{type_defn.name}") }
50
+ visit_fields(type_defn)
51
+ when GraphQL::InterfaceType
52
+ visit_fields(type_defn)
53
+ when GraphQL::UnionType
54
+ type_defn.possible_types.each { |t| visit(t, "Possible type for #{type_defn.name}") }
55
+ when GraphQL::InputObjectType
56
+ type_defn.arguments.each do |name, arg|
57
+ visit(arg.type, "Input field #{type_defn.name}.#{name}")
58
+ end
59
+ end
60
+ elsif !prev_type.equal?(type_defn)
61
+ # If the previous entry in the map isn't the same object we just found, raise.
62
+ raise("Duplicate type definition found for name '#{type_defn.name}'")
63
+ end
64
+ else
65
+ message = "Unexpected schema traversal member: #{member} (#{member.class.name})"
66
+ raise GraphQL::Schema::InvalidTypeError.new(message)
67
+ end
68
+ end
69
+
70
+ def visit_fields(type_defn)
71
+ type_defn.all_fields.each do |field_defn|
72
+ instrumented_field_defn = @field_instrumenters.reduce(field_defn) do |defn, inst|
73
+ inst.instrument(type_defn, defn)
74
+ end
75
+ @instrumented_field_map[type_defn.name][instrumented_field_defn.name] = instrumented_field_defn
76
+ visit(instrumented_field_defn.type, "Field #{type_defn.name}.#{instrumented_field_defn.name}'s return type")
77
+ instrumented_field_defn.arguments.each do |name, arg|
78
+ visit(arg.type, "Argument #{name} on #{type_defn.name}.#{instrumented_field_defn.name}")
79
+ end
80
+ end
81
+ end
82
+
83
+ def validate_type(member, context_description)
84
+ error_message = GraphQL::Schema::Validation.validate(member)
85
+ if error_message
86
+ raise GraphQL::Schema::InvalidTypeError.new("#{context_description} is invalid: #{error_message}")
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end