Skip to content

Commit 3e5dad2

Browse files
committed
Change fields to path in validation responses
This brings it into line with the GraphQL spec: https://github.com/facebook/graphql/blob/master/spec/Section%207%20--%20Response.md#user-content-errors
1 parent c116c48 commit 3e5dad2

29 files changed

Lines changed: 430 additions & 86 deletions

javascript_client/yarn.lock

Lines changed: 342 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/graphql/static_validation/base_visitor.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ def on_fragment_with_type(node)
174174

175175
# Error `message` is located at `node`
176176
def add_error(message, nodes, path: nil)
177+
# Add an optional hash here that message adds onto the response object - then easy to vary for all items
177178
path ||= @path.dup
178179
nodes = Array(nodes)
179180
m = GraphQL::StaticValidation::Message.new(message, nodes: nodes, path: path)

lib/graphql/static_validation/message.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ class Message
77
module MessageHelper
88
# Error `message` is located at `node`
99
def message(message, nodes, context: nil, path: nil)
10+
# TODO: also add object hash of extras as in base_visitor
1011
path ||= context.path
1112
nodes = Array(nodes)
1213
GraphQL::StaticValidation::Message.new(message, nodes: nodes, path: path)
@@ -26,7 +27,7 @@ def to_h
2627
{
2728
"message" => message,
2829
"locations" => locations,
29-
"fields" => path,
30+
"path" => path,
3031
}
3132
end
3233

spec/graphql/execution/multiplex_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ def multiplex(*a)
9494
"errors" => [{
9595
"message"=>"Field must have selections (field 'nullableNestedSum' returns LazySum but has no selections. Did you mean 'nullableNestedSum { ... }'?)",
9696
"locations"=>[{"line"=>1, "column"=>4}],
97-
"fields"=>["query", "validationError"]
97+
"path"=>["query", "validationError"]
9898
}]
9999
},
100100
]

spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,42 +27,42 @@
2727
query_root_error = {
2828
"message"=>"Argument 'id' on Field 'stringCheese' has an invalid value. Expected type 'Int!'.",
2929
"locations"=>[{"line"=>3, "column"=>7}],
30-
"fields"=>["query getCheese", "stringCheese", "id"],
30+
"path"=>["query getCheese", "stringCheese", "id"],
3131
}
3232
assert_includes(errors, query_root_error)
3333

3434
directive_error = {
3535
"message"=>"Argument 'if' on Directive 'skip' has an invalid value. Expected type 'Boolean!'.",
3636
"locations"=>[{"line"=>4, "column"=>30}],
37-
"fields"=>["query getCheese", "cheese", "source", "if"],
37+
"path"=>["query getCheese", "cheese", "source", "if"],
3838
}
3939
assert_includes(errors, directive_error)
4040

4141
input_object_error = {
4242
"message"=>"Argument 'product' on Field 'badSource' has an invalid value. Expected type '[DairyProductInput]'.",
4343
"locations"=>[{"line"=>6, "column"=>7}],
44-
"fields"=>["query getCheese", "badSource", "product"],
44+
"path"=>["query getCheese", "badSource", "product"],
4545
}
4646
assert_includes(errors, input_object_error)
4747

4848
input_object_field_error = {
4949
"message"=>"Argument 'source' on InputObject 'DairyProductInput' has an invalid value. Expected type 'DairyAnimal!'.",
5050
"locations"=>[{"line"=>6, "column"=>40}],
51-
"fields"=>["query getCheese", "badSource", "product", "source"],
51+
"path"=>["query getCheese", "badSource", "product", "source"],
5252
}
5353
assert_includes(errors, input_object_field_error)
5454

5555
missing_required_field_error = {
5656
"message"=>"Argument 'product' on Field 'missingSource' has an invalid value. Expected type '[DairyProductInput]'.",
5757
"locations"=>[{"line"=>7, "column"=>7}],
58-
"fields"=>["query getCheese", "missingSource", "product"],
58+
"path"=>["query getCheese", "missingSource", "product"],
5959
}
6060
assert_includes(errors, missing_required_field_error)
6161

6262
fragment_error = {
6363
"message"=>"Argument 'source' on Field 'similarCheese' has an invalid value. Expected type '[DairyAnimal!]!'.",
6464
"locations"=>[{"line"=>13, "column"=>7}],
65-
"fields"=>["fragment cheeseFields", "similarCheese", "source"],
65+
"path"=>["fragment cheeseFields", "similarCheese", "source"],
6666
}
6767
assert_includes(errors, fragment_error)
6868
end
@@ -120,7 +120,7 @@
120120
assert_equal [{
121121
"message"=>"Argument 'arg' on Field 'field' has an invalid value. Expected type 'Int!'.",
122122
"locations"=>[{"line"=>3, "column"=>11}],
123-
"fields"=>["query", "field", "arg"],
123+
"path"=>["query", "field", "arg"],
124124
}], errors
125125
end
126126
end
@@ -143,7 +143,7 @@
143143
assert_equal [{
144144
"message"=>"Argument 'arg' on Field 'field' has an invalid value. Expected type '[Int!]'.",
145145
"locations"=>[{"line"=>3, "column"=>11}],
146-
"fields"=>["query", "field", "arg"],
146+
"path"=>["query", "field", "arg"],
147147
}], errors
148148
end
149149
end
@@ -192,13 +192,13 @@
192192
assert_includes errors, {
193193
"message"=> "Argument 'arg' on Field 'field' has an invalid value. Expected type 'Input'.",
194194
"locations"=>[{"line"=>3, "column"=>11}],
195-
"fields"=>["query", "field", "arg"]
195+
"path"=>["query", "field", "arg"]
196196
}
197197

198198
assert_includes errors, {
199199
"message"=>"Argument 'b' on InputObject 'Input' has an invalid value. Expected type 'Int!'.",
200200
"locations"=>[{"line"=>3, "column"=>22}],
201-
"fields"=>["query", "field", "arg", "b"]
201+
"path"=>["query", "field", "arg", "b"]
202202
}
203203
end
204204
end
@@ -215,7 +215,7 @@
215215
assert_includes(errors, {
216216
"message"=>"Argument 'name' on Field '__type' has an invalid value. Expected type 'String!'.",
217217
"locations"=>[{"line"=>3, "column"=>9}],
218-
"fields"=>["query", "__type", "name"],
218+
"path"=>["query", "__type", "name"],
219219
})
220220
end
221221
end
@@ -266,7 +266,7 @@
266266
assert_includes errors, {
267267
"message"=> "cannot coerce to Float",
268268
"locations"=>[{"line"=>3, "column"=>9}],
269-
"fields"=>["query", "time", "value"]
269+
"path"=>["query", "time", "value"]
270270
}
271271
end
272272
end

spec/graphql/static_validation/rules/argument_names_are_unique_spec.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
error = errors.first
2020
assert_equal 'There can be only one argument named "id"', error["message"]
2121
assert_equal [{ "line" => 2, "column" => 18}, { "line" => 2, "column" => 25 }], error["locations"]
22-
assert_equal ["query GetStuff", "c1"], error["fields"]
22+
assert_equal ["query GetStuff", "c1"], error["path"]
2323
end
2424
end
2525

@@ -38,7 +38,7 @@
3838
error = errors.first
3939
assert_equal 'There can be only one argument named "if"', error["message"]
4040
assert_equal [{ "line" => 2, "column" => 34}, { "line" => 2, "column" => 44 }], error["locations"]
41-
assert_equal ["query GetStuff", "c1"], error["fields"]
41+
assert_equal ["query GetStuff", "c1"], error["path"]
4242
end
4343
end
4444
end

spec/graphql/static_validation/rules/arguments_are_defined_spec.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,28 +25,28 @@
2525
query_root_error = {
2626
"message"=>"Field 'cheese' doesn't accept argument 'silly'",
2727
"locations"=>[{"line"=>4, "column"=>14}],
28-
"fields"=>["query getCheese", "cheese", "silly"],
28+
"path"=>["query getCheese", "cheese", "silly"],
2929
}
3030
assert_includes(errors, query_root_error)
3131

3232
input_obj_record = {
3333
"message"=>"InputObject 'DairyProductInput' doesn't accept argument 'wacky'",
3434
"locations"=>[{"line"=>5, "column"=>30}],
35-
"fields"=>["query getCheese", "searchDairy", "product", "wacky"],
35+
"path"=>["query getCheese", "searchDairy", "product", "wacky"],
3636
}
3737
assert_includes(errors, input_obj_record)
3838

3939
fragment_error = {
4040
"message"=>"Field 'similarCheese' doesn't accept argument 'nonsense'",
4141
"locations"=>[{"line"=>9, "column"=>36}],
42-
"fields"=>["fragment cheeseFields", "similarCheese", "nonsense"],
42+
"path"=>["fragment cheeseFields", "similarCheese", "nonsense"],
4343
}
4444
assert_includes(errors, fragment_error)
4545

4646
directive_error = {
4747
"message"=>"Directive 'skip' doesn't accept argument 'something'",
4848
"locations"=>[{"line"=>10, "column"=>16}],
49-
"fields"=>["fragment cheeseFields", "id", "something"],
49+
"path"=>["fragment cheeseFields", "id", "something"],
5050
}
5151
assert_includes(errors, directive_error)
5252
end
@@ -62,7 +62,7 @@
6262
assert_includes(errors, {
6363
"message"=>"Field '__type' doesn't accept argument 'somethingInvalid'",
6464
"locations"=>[{"line"=>3, "column"=>16}],
65-
"fields"=>["query", "__type", "somethingInvalid"],
65+
"path"=>["query", "__type", "somethingInvalid"],
6666
})
6767
end
6868
end

spec/graphql/static_validation/rules/directives_are_defined_spec.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@
2020
{
2121
"message"=>"Directive @nonsense is not defined",
2222
"locations"=>[{"line"=>5, "column"=>16}],
23-
"fields"=>["query getCheese", "okCheese", "source"],
23+
"path"=>["query getCheese", "okCheese", "source"],
2424
}, {
2525
"message"=>"Directive @moreNonsense is not defined",
2626
"locations"=>[{"line"=>7, "column"=>18}],
27-
"fields"=>["query getCheese", "okCheese", "... on Cheese", "flavor"],
27+
"path"=>["query getCheese", "okCheese", "... on Cheese", "flavor"],
2828
}
2929
]
3030
assert_equal(expected, errors)

spec/graphql/static_validation/rules/directives_are_in_valid_locations_spec.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,12 @@
2626
{
2727
"message"=> "'@skip' can't be applied to queries (allowed: fields, fragment spreads, inline fragments)",
2828
"locations"=>[{"line"=>2, "column"=>21}],
29-
"fields"=>["query getCheese"],
29+
"path"=>["query getCheese"],
3030
},
3131
{
3232
"message"=>"'@skip' can't be applied to fragment definitions (allowed: fields, fragment spreads, inline fragments)",
3333
"locations"=>[{"line"=>13, "column"=>33}],
34-
"fields"=>["fragment whatever"],
34+
"path"=>["fragment whatever"],
3535
},
3636
]
3737
assert_equal(expected, errors)

spec/graphql/static_validation/rules/fields_are_defined_on_type_spec.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
{
3232
"message"=>"Field 'notDefinedField' doesn't exist on type 'Query'",
3333
"locations"=>[{"line"=>1, "column"=>18}],
34-
"fields"=>["query getStuff", "notDefinedField"],
34+
"path"=>["query getStuff", "notDefinedField"],
3535
}
3636
]
3737
assert_equal(expected_errors, errors)
@@ -46,7 +46,7 @@
4646
{
4747
"message"=>"Field 'amountThatILikeIt' doesn't exist on type 'Edible'",
4848
"locations"=>[{"line"=>1, "column"=>35}],
49-
"fields"=>["query getStuff", "favoriteEdible", "amountThatILikeIt"],
49+
"path"=>["query getStuff", "favoriteEdible", "amountThatILikeIt"],
5050
}
5151
]
5252
assert_equal(expected_errors, errors)
@@ -67,7 +67,7 @@
6767
"locations"=>[
6868
{"line"=>3, "column"=>7}
6969
],
70-
"fields"=>["fragment dpFields", "source"],
70+
"path"=>["fragment dpFields", "source"],
7171
}
7272
]
7373
assert_equal(expected_errors, errors)
@@ -120,7 +120,7 @@
120120
"locations"=>[
121121
{"line"=>2, "column"=>33}
122122
],
123-
"fields"=>["query", "cheese", "__schema"],
123+
"path"=>["query", "cheese", "__schema"],
124124
}
125125
]
126126
assert_equal(expected_errors, errors)
@@ -151,7 +151,7 @@
151151
"locations"=>[
152152
{"line"=>2, "column"=>33}
153153
],
154-
"fields"=>["query", "cheese", "__type"],
154+
"path"=>["query", "cheese", "__type"],
155155
}
156156
]
157157
assert_equal(expected_errors, errors)

0 commit comments

Comments
 (0)