graphql 1.6.4 → 1.6.5

Sign up to get free protection for your applications and to get access to all the features.
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