graphql 0.18.4 → 0.18.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/graphql.rb +1 -2
- data/lib/graphql/argument.rb +2 -2
- data/lib/graphql/base_type.rb +17 -0
- data/lib/graphql/define.rb +1 -1
- data/lib/graphql/directive.rb +6 -0
- data/lib/graphql/enum_type.rb +48 -4
- data/lib/graphql/field.rb +81 -19
- data/lib/graphql/field/resolve.rb +1 -1
- data/lib/graphql/input_object_type.rb +17 -3
- data/lib/graphql/interface_type.rb +12 -2
- data/lib/graphql/list_type.rb +23 -4
- data/lib/graphql/non_null_type.rb +27 -2
- data/lib/graphql/query.rb +0 -1
- data/lib/graphql/query/arguments.rb +1 -1
- data/lib/graphql/query/serial_execution/value_resolution.rb +3 -1
- data/lib/graphql/relay/global_node_identification.rb +29 -16
- data/lib/graphql/scalar_type.rb +24 -1
- data/lib/graphql/schema.rb +109 -19
- data/lib/graphql/schema/printer.rb +3 -3
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
- data/lib/graphql/union_type.rb +19 -6
- data/lib/graphql/version.rb +1 -1
- data/readme.md +5 -6
- data/spec/graphql/analysis/query_complexity_spec.rb +1 -1
- data/spec/graphql/argument_spec.rb +1 -1
- data/spec/graphql/field_spec.rb +1 -1
- data/spec/graphql/interface_type_spec.rb +0 -19
- data/spec/graphql/query/context_spec.rb +1 -1
- data/spec/graphql/query/executor_spec.rb +1 -1
- data/spec/graphql/query/serial_execution/value_resolution_spec.rb +8 -4
- data/spec/graphql/relay/array_connection_spec.rb +17 -17
- data/spec/graphql/relay/connection_type_spec.rb +1 -1
- data/spec/graphql/relay/global_node_identification_spec.rb +3 -21
- data/spec/graphql/relay/mutation_spec.rb +2 -2
- data/spec/graphql/relay/page_info_spec.rb +9 -9
- data/spec/graphql/relay/relation_connection_spec.rb +31 -31
- data/spec/graphql/schema/printer_spec.rb +1 -1
- data/spec/graphql/schema/reduce_types_spec.rb +1 -1
- data/spec/graphql/schema/timeout_middleware_spec.rb +1 -1
- data/spec/graphql/schema_spec.rb +18 -0
- data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +6 -6
- data/spec/graphql/union_type_spec.rb +0 -4
- data/spec/spec_helper.rb +1 -1
- data/spec/support/dairy_app.rb +13 -8
- data/spec/support/star_wars_schema.rb +18 -16
- metadata +2 -2
data/lib/graphql/query.rb
CHANGED
@@ -50,7 +50,6 @@ module GraphQL
|
|
50
50
|
@operations = {}
|
51
51
|
@provided_variables = variables
|
52
52
|
@query_string = query_string
|
53
|
-
|
54
53
|
@document = document || GraphQL.parse(query_string)
|
55
54
|
@document.definitions.each do |part|
|
56
55
|
if part.is_a?(GraphQL::Language::Nodes::FragmentDefinition)
|
@@ -54,7 +54,9 @@ module GraphQL
|
|
54
54
|
|
55
55
|
class HasPossibleTypeResolution < BaseResolution
|
56
56
|
def non_null_result
|
57
|
-
|
57
|
+
# When deprecations are removed:
|
58
|
+
# resolved_type = execution_context.schema.resolve_type(value)
|
59
|
+
resolved_type = field_type.legacy_resolve_type(value, execution_context)
|
58
60
|
|
59
61
|
unless resolved_type.is_a?(GraphQL::ObjectType)
|
60
62
|
raise GraphQL::ObjectType::UnresolvedTypeError.new(irep_node.definition_name, field_type, parent_type)
|
@@ -12,6 +12,10 @@ module GraphQL
|
|
12
12
|
accepts_definitions(:object_from_id, :type_from_object, :to_global_id, :from_global_id, :description)
|
13
13
|
lazy_defined_attr_accessor :description
|
14
14
|
|
15
|
+
# Memoize the schema to support deprecated node_ident-level resolve functions
|
16
|
+
# TODO: remove after Schema.resolve_type is required
|
17
|
+
attr_accessor :schema
|
18
|
+
|
15
19
|
class << self
|
16
20
|
attr_accessor :id_separator
|
17
21
|
end
|
@@ -28,12 +32,20 @@ module GraphQL
|
|
28
32
|
@interface ||= begin
|
29
33
|
ensure_defined
|
30
34
|
ident = self
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
35
|
+
if @type_from_object_proc
|
36
|
+
# TODO: remove after Schema.resolve_type is required
|
37
|
+
GraphQL::InterfaceType.define do
|
38
|
+
name "Node"
|
39
|
+
field :id, !types.ID
|
40
|
+
resolve_type -> (obj, ctx) {
|
41
|
+
ident.type_from_object(obj)
|
42
|
+
}
|
43
|
+
end
|
44
|
+
else
|
45
|
+
GraphQL::InterfaceType.define do
|
46
|
+
name "Node"
|
47
|
+
field :id, !types.ID
|
48
|
+
end
|
37
49
|
end
|
38
50
|
end
|
39
51
|
end
|
@@ -90,22 +102,23 @@ module GraphQL
|
|
90
102
|
|
91
103
|
# Use the provided config to
|
92
104
|
# get a type for a given object
|
105
|
+
# TODO: remove after Schema.resolve_type is required
|
93
106
|
def type_from_object(object)
|
94
107
|
ensure_defined
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
raise "type_from_object(#{object}) returned #{type_str}, but it should return a GraphQL type"
|
101
|
-
else
|
102
|
-
type_result
|
108
|
+
warn("type_from_object(object) is deprecated; use Schema.resolve_type(object) instead")
|
109
|
+
|
110
|
+
if @type_from_object_proc
|
111
|
+
schema.resolve_type = @type_from_object_proc
|
112
|
+
@type_from_object_proc = nil
|
103
113
|
end
|
114
|
+
|
115
|
+
schema.resolve_type(object)
|
104
116
|
end
|
105
117
|
|
106
|
-
def type_from_object=(
|
118
|
+
def type_from_object=(new_type_from_object_proc)
|
107
119
|
ensure_defined
|
108
|
-
|
120
|
+
warn("type_from_object(object) is deprecated; use Schema.resolve_type(object) instead")
|
121
|
+
@type_from_object_proc = new_type_from_object_proc
|
109
122
|
end
|
110
123
|
|
111
124
|
# Use the provided config to
|
data/lib/graphql/scalar_type.rb
CHANGED
@@ -1,5 +1,28 @@
|
|
1
1
|
module GraphQL
|
2
|
-
#
|
2
|
+
# # GraphQL::ScalarType
|
3
|
+
#
|
4
|
+
# Scalars are plain values. They are leaf nodes in a GraphQL query tree.
|
5
|
+
#
|
6
|
+
# ## Built-in Scalars
|
7
|
+
#
|
8
|
+
# `GraphQL` comes with standard built-in scalars:
|
9
|
+
#
|
10
|
+
# |Constant | `.define` helper|
|
11
|
+
# |-------|--------|
|
12
|
+
# |`GraphQL::STRING_TYPE` | `types.String`|
|
13
|
+
# |`GraphQL::INT_TYPE` | `types.Int`|
|
14
|
+
# |`GraphQL::FLOAT_TYPE` | `types.Float`|
|
15
|
+
# |`GraphQL::ID_TYPE` | `types.ID`|
|
16
|
+
# |`GraphQL::BOOLEAN_TYPE` | `types.Boolean`|
|
17
|
+
#
|
18
|
+
# (`types` is an instance of `GraphQL::Definition::TypeDefiner`; `.String`, `.Float`, etc are methods which return built-in scalars.)
|
19
|
+
#
|
20
|
+
# ## Custom Scalars
|
21
|
+
#
|
22
|
+
# You can define custom scalars for your GraphQL server. It requires some special functions:
|
23
|
+
#
|
24
|
+
# - `coerce_input` is used to prepare incoming values for GraphQL execution. (Incoming values come from variables or literal values in the query string.)
|
25
|
+
# - `coerce_result` is used to turn Ruby values _back_ into serializable values for query responses.
|
3
26
|
#
|
4
27
|
# @example defining a type for Time
|
5
28
|
# TimeType = GraphQL::ScalarType.define do
|
data/lib/graphql/schema.rb
CHANGED
@@ -11,33 +11,88 @@ require "graphql/schema/validation"
|
|
11
11
|
|
12
12
|
module GraphQL
|
13
13
|
# A GraphQL schema which may be queried with {GraphQL::Query}.
|
14
|
+
#
|
15
|
+
# The {Schema} contains:
|
16
|
+
#
|
17
|
+
# - types for exposing your application
|
18
|
+
# - query analyzers for assessing incoming queries (including max depth & max complexity restrictions)
|
19
|
+
# - execution strategies for running incoming queries
|
20
|
+
# - middleware for interacting with execution
|
21
|
+
#
|
22
|
+
# Schemas start with root types, {Schema#query}, {Schema#mutation} and {Schema#subscription}.
|
23
|
+
# The schema will traverse the tree of fields & types, using those as starting points.
|
24
|
+
# Any undiscoverable types may be provided with the `types` configuration.
|
25
|
+
#
|
26
|
+
# Schemas can restrict large incoming queries with `max_depth` and `max_complexity` configurations.
|
27
|
+
# (These configurations can be overridden by specific calls to {Schema#execute})
|
28
|
+
#
|
29
|
+
# Schemas can specify how queries should be executed against them.
|
30
|
+
# `query_execution_strategy`, `mutation_execution_strategy` and `subscription_execution_strategy`
|
31
|
+
# each apply to corresponding root types.
|
32
|
+
#
|
33
|
+
# A schema accepts a `Relay::GlobalNodeIdentification` instance for use with Relay IDs.
|
34
|
+
#
|
35
|
+
# @example defining a schema
|
36
|
+
# MySchema = GraphQL::Schema.define do
|
37
|
+
# query QueryType
|
38
|
+
# middleware PermissionMiddleware
|
39
|
+
# rescue_from(ActiveRecord::RecordNotFound) { "Not found" }
|
40
|
+
# # If types are only connected by way of interfaces, they must be added here
|
41
|
+
# orphan_types ImageType, AudioType
|
42
|
+
# end
|
43
|
+
#
|
14
44
|
class Schema
|
15
|
-
|
45
|
+
include GraphQL::Define::InstanceDefinable
|
46
|
+
accepts_definitions \
|
47
|
+
:query, :mutation, :subscription,
|
48
|
+
:query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
|
49
|
+
:max_depth, :max_complexity,
|
50
|
+
:node_identification,
|
51
|
+
:orphan_types, :resolve_type,
|
52
|
+
query_analyzer: -> (schema, analyzer) { schema.query_analyzers << analyzer },
|
53
|
+
middleware: -> (schema, middleware) { schema.middleware << middleware },
|
54
|
+
rescue_from: -> (schema, err_class, &block) { schema.rescue_from(err_class, &block)}
|
55
|
+
|
56
|
+
lazy_defined_attr_accessor \
|
57
|
+
:query, :mutation, :subscription,
|
58
|
+
:query_execution_strategy, :mutation_execution_strategy, :subscription_execution_strategy,
|
59
|
+
:max_depth, :max_complexity,
|
60
|
+
:orphan_types,
|
61
|
+
:query_analyzers, :middleware
|
62
|
+
|
16
63
|
|
17
64
|
DIRECTIVES = [GraphQL::Directive::SkipDirective, GraphQL::Directive::IncludeDirective]
|
18
65
|
DYNAMIC_FIELDS = ["__type", "__typename", "__schema"]
|
66
|
+
RESOLVE_TYPE_PROC_REQUIRED = -> (obj) { raise("Schema.resolve_type is undefined, can't resolve type for #{obj}") }
|
19
67
|
|
20
|
-
attr_reader :
|
21
|
-
attr_accessor :max_depth
|
22
|
-
attr_accessor :max_complexity
|
23
|
-
|
24
|
-
# Override these if you don't want the default executor:
|
25
|
-
attr_accessor :query_execution_strategy,
|
26
|
-
:mutation_execution_strategy,
|
27
|
-
:subscription_execution_strategy
|
68
|
+
attr_reader :directives, :static_validator
|
28
69
|
|
29
70
|
# @return [GraphQL::Relay::GlobalNodeIdentification] the node identification instance for this schema, when using Relay
|
30
|
-
|
71
|
+
def node_identification
|
72
|
+
ensure_defined
|
73
|
+
@node_identification
|
74
|
+
end
|
75
|
+
|
76
|
+
def node_identification=(new_node_ident)
|
77
|
+
new_node_ident.schema = self
|
78
|
+
@node_identification = new_node_ident
|
79
|
+
end
|
31
80
|
|
32
81
|
# @return [Array<#call>] Middlewares suitable for MiddlewareChain, applied to fields during execution
|
33
|
-
|
82
|
+
def middleware
|
83
|
+
ensure_defined
|
84
|
+
@middleware
|
85
|
+
end
|
34
86
|
|
35
87
|
# @param query [GraphQL::ObjectType] the query root for the schema
|
36
88
|
# @param mutation [GraphQL::ObjectType] the mutation root for the schema
|
37
89
|
# @param subscription [GraphQL::ObjectType] the subscription root for the schema
|
38
90
|
# @param max_depth [Integer] maximum query nesting (if it's greater, raise an error)
|
39
91
|
# @param types [Array<GraphQL::BaseType>] additional types to include in this schema
|
40
|
-
def initialize(query
|
92
|
+
def initialize(query: nil, mutation: nil, subscription: nil, max_depth: nil, max_complexity: nil, types: [])
|
93
|
+
if query
|
94
|
+
warn("Schema.new is deprecated, use Schema.define instead")
|
95
|
+
end
|
41
96
|
@query = query
|
42
97
|
@mutation = mutation
|
43
98
|
@subscription = subscription
|
@@ -49,18 +104,28 @@ module GraphQL
|
|
49
104
|
@rescue_middleware = GraphQL::Schema::RescueMiddleware.new
|
50
105
|
@middleware = [@rescue_middleware]
|
51
106
|
@query_analyzers = []
|
107
|
+
@resolve_type_proc = RESOLVE_TYPE_PROC_REQUIRED
|
52
108
|
# Default to the built-in execution strategy:
|
53
|
-
|
54
|
-
|
55
|
-
|
109
|
+
@query_execution_strategy = GraphQL::Query::SerialExecution
|
110
|
+
@mutation_execution_strategy = GraphQL::Query::SerialExecution
|
111
|
+
@subscription_execution_strategy = GraphQL::Query::SerialExecution
|
112
|
+
end
|
113
|
+
|
114
|
+
def rescue_from(*args, &block)
|
115
|
+
ensure_defined
|
116
|
+
@rescue_middleware.rescue_from(*args, &block)
|
56
117
|
end
|
57
118
|
|
58
|
-
|
119
|
+
def remove_handler(*args, &block)
|
120
|
+
ensure_defined
|
121
|
+
@rescue_middleware.remove_handler(*args, &block)
|
122
|
+
end
|
59
123
|
|
60
124
|
# @return [GraphQL::Schema::TypeMap] `{ name => type }` pairs of types in this schema
|
61
125
|
def types
|
62
126
|
@types ||= begin
|
63
|
-
|
127
|
+
ensure_defined
|
128
|
+
all_types = orphan_types + [query, mutation, subscription, GraphQL::Introspection::SchemaType]
|
64
129
|
GraphQL::Schema::ReduceTypes.reduce(all_types.compact)
|
65
130
|
end
|
66
131
|
end
|
@@ -69,13 +134,14 @@ module GraphQL
|
|
69
134
|
# See {Query#initialize} for arguments.
|
70
135
|
# @return [Hash] query result, ready to be serialized as JSON
|
71
136
|
def execute(*args)
|
72
|
-
|
73
|
-
|
137
|
+
query_obj = GraphQL::Query.new(self, *args)
|
138
|
+
query_obj.result
|
74
139
|
end
|
75
140
|
|
76
141
|
# Resolve field named `field_name` for type `parent_type`.
|
77
142
|
# Handles dynamic fields `__typename`, `__type` and `__schema`, too
|
78
143
|
def get_field(parent_type, field_name)
|
144
|
+
ensure_defined
|
79
145
|
defined_field = parent_type.get_field(field_name)
|
80
146
|
if defined_field
|
81
147
|
defined_field
|
@@ -91,12 +157,15 @@ module GraphQL
|
|
91
157
|
end
|
92
158
|
|
93
159
|
def type_from_ast(ast_node)
|
160
|
+
ensure_defined
|
94
161
|
GraphQL::Schema::TypeExpression.build_type(self, ast_node)
|
95
162
|
end
|
96
163
|
|
164
|
+
# TODO: when `resolve_type` is schema level, can this be removed?
|
97
165
|
# @param type_defn [GraphQL::InterfaceType, GraphQL::UnionType] the type whose members you want to retrieve
|
98
166
|
# @return [Array<GraphQL::ObjectType>] types which belong to `type_defn` in this schema
|
99
167
|
def possible_types(type_defn)
|
168
|
+
ensure_defined
|
100
169
|
@interface_possible_types ||= GraphQL::Schema::PossibleTypes.new(self)
|
101
170
|
@interface_possible_types.possible_types(type_defn)
|
102
171
|
end
|
@@ -126,5 +195,26 @@ module GraphQL
|
|
126
195
|
raise ArgumentError, "unknown operation type: #{operation}"
|
127
196
|
end
|
128
197
|
end
|
198
|
+
|
199
|
+
# Determine the GraphQL type for a given object.
|
200
|
+
# This is required for unions and interfaces (include Relay's node interface)
|
201
|
+
# @return [GraphQL::ObjectType] The type for exposing `object` in GraphQL
|
202
|
+
def resolve_type(object, ctx)
|
203
|
+
ensure_defined
|
204
|
+
type_result = @resolve_type_proc.call(object, ctx)
|
205
|
+
if type_result.nil?
|
206
|
+
nil
|
207
|
+
elsif !type_result.is_a?(GraphQL::BaseType)
|
208
|
+
type_str = "#{type_result} (#{type_result.class.name})"
|
209
|
+
raise "resolve_type(#{object}) returned #{type_str}, but it should return a GraphQL type"
|
210
|
+
else
|
211
|
+
type_result
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def resolve_type=(new_resolve_type_proc)
|
216
|
+
ensure_defined
|
217
|
+
@resolve_type_proc = new_resolve_type_proc
|
218
|
+
end
|
129
219
|
end
|
130
220
|
end
|
@@ -3,8 +3,8 @@ module GraphQL
|
|
3
3
|
# Used to convert your {GraphQL::Schema} to a GraphQL schema string
|
4
4
|
#
|
5
5
|
# @example print your schema to standard output
|
6
|
-
#
|
7
|
-
# puts GraphQL::Schema::Printer.print_schema(
|
6
|
+
# MySchema = GraphQL::Schema.define(query: QueryType)
|
7
|
+
# puts GraphQL::Schema::Printer.print_schema(MySchema)
|
8
8
|
#
|
9
9
|
module Printer
|
10
10
|
extend self
|
@@ -20,7 +20,7 @@ module GraphQL
|
|
20
20
|
query_root = ObjectType.define do
|
21
21
|
name "Query"
|
22
22
|
end
|
23
|
-
schema = Schema.
|
23
|
+
schema = GraphQL::Schema.define(query: query_root)
|
24
24
|
print_filtered_schema(schema, method(:is_introspection_type))
|
25
25
|
end
|
26
26
|
|
@@ -10,7 +10,7 @@ module GraphQL
|
|
10
10
|
if !valid
|
11
11
|
kind_of_node = node_type(parent)
|
12
12
|
error_arg_name = parent_name(parent, defn)
|
13
|
-
context.errors << message("Argument '#{node.name}' on #{kind_of_node} '#{error_arg_name}' has an invalid value", parent, context: context)
|
13
|
+
context.errors << message("Argument '#{node.name}' on #{kind_of_node} '#{error_arg_name}' has an invalid value. Expected type '#{arg_defn.type}'.", parent, context: context)
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
data/lib/graphql/union_type.rb
CHANGED
@@ -1,14 +1,27 @@
|
|
1
1
|
module GraphQL
|
2
|
-
# A collection of
|
2
|
+
# A Union is is a collection of object types which may appear in the same place.
|
3
3
|
#
|
4
|
-
#
|
4
|
+
# The members of a union are declared with `possible_types`.
|
5
5
|
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
6
|
+
# @example A union of object types
|
7
|
+
# MediaUnion = GraphQL::UnionType.define do
|
8
|
+
# name "Media"
|
9
|
+
# description "Media objects which you can enjoy"
|
10
|
+
# possible_types [AudioType, ImageType, VideoType]
|
10
11
|
# end
|
11
12
|
#
|
13
|
+
# A union itself has no fields; only its members have fields.
|
14
|
+
# So, when you query, you must use fragment spreads to access fields.
|
15
|
+
#
|
16
|
+
# @example Querying for fields on union members
|
17
|
+
# {
|
18
|
+
# searchMedia(name: "Jens Lekman") {
|
19
|
+
# ... on Audio { name, duration }
|
20
|
+
# ... on Image { name, height, width }
|
21
|
+
# ... on Video { name, length, quality }
|
22
|
+
# }
|
23
|
+
# }
|
24
|
+
#
|
12
25
|
class UnionType < GraphQL::BaseType
|
13
26
|
include GraphQL::BaseType::HasPossibleTypes
|
14
27
|
accepts_definitions :possible_types, :resolve_type
|
data/lib/graphql/version.rb
CHANGED
data/readme.md
CHANGED
@@ -62,10 +62,10 @@ QueryType = GraphQL::ObjectType.define do
|
|
62
62
|
end
|
63
63
|
|
64
64
|
# Then create your schema
|
65
|
-
Schema = GraphQL::Schema.
|
66
|
-
query
|
67
|
-
max_depth
|
68
|
-
|
65
|
+
Schema = GraphQL::Schema.define do
|
66
|
+
query QueryType,
|
67
|
+
max_depth 8,
|
68
|
+
end
|
69
69
|
```
|
70
70
|
|
71
71
|
#### Execute queries
|
@@ -127,10 +127,9 @@ If you're building a backend for [Relay](http://facebook.github.io/relay/), you'
|
|
127
127
|
- Reduce ad-hoc traversals?
|
128
128
|
- Validators are order-dependent, is this a smell?
|
129
129
|
- Tests for interference between validators are poor
|
130
|
-
- Maybe this is a candidate for a rewrite?
|
130
|
+
- Maybe this is a candidate for a rewrite?
|
131
131
|
- Add Rails-y argument validations, eg `less_than: 100`, `max_length: 255`, `one_of: [...]`
|
132
132
|
- Must be customizable
|
133
|
-
- Refactor `Query#perform_validation`, how can that be organized better?
|
134
133
|
- Relay:
|
135
134
|
- `GlobalNodeIdentification.to_global_id` should receive the type name and _object_, not `id`. (Or, maintain the "`type_name, id` in, `type_name, id` out" pattern?)
|
136
135
|
- Reduce duplication in ArrayConnection / RelationConnection
|
@@ -255,7 +255,7 @@ describe GraphQL::Analysis::QueryComplexity do
|
|
255
255
|
end
|
256
256
|
end
|
257
257
|
|
258
|
-
GraphQL::Schema.
|
258
|
+
GraphQL::Schema.define(query: query_type, orphan_types: [double_complexity_type])
|
259
259
|
}
|
260
260
|
let(:query_string) {%|
|
261
261
|
{
|
data/spec/graphql/field_spec.rb
CHANGED
@@ -82,7 +82,7 @@ describe GraphQL::Field do
|
|
82
82
|
invalid_field.name = :symbol_name
|
83
83
|
|
84
84
|
dummy_query.fields["symbol_name"] = invalid_field
|
85
|
-
dummy_schema = GraphQL::Schema.
|
85
|
+
dummy_schema = GraphQL::Schema.define(query: dummy_query)
|
86
86
|
|
87
87
|
err = assert_raises(GraphQL::Schema::InvalidTypeError) { dummy_schema.types }
|
88
88
|
assert_equal "QueryType is invalid: field :symbol_name name must return String, not Symbol (:symbol_name)", err.message
|