Skip to content

Commit 891d4a6

Browse files
committed
[Validation] Report errors rather than return them
Related GraphQL-js commit graphql/graphql-js@5e545cc
1 parent ccf167c commit 891d4a6

27 files changed

+104
-112
lines changed

graphql/core/validation/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@ def visit_using_rules(schema, type_info, ast, rules):
1919
errors = []
2020
rules = [rule(context) for rule in rules]
2121
visit(ast, ValidationVisitor(rules, context, type_info, errors))
22-
return errors
22+
return context.get_errors()

graphql/core/validation/context.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,18 +31,25 @@ def leave(self, node, key, parent, path, ancestors):
3131

3232

3333
class ValidationContext(object):
34-
__slots__ = '_schema', '_ast', '_type_info', '_fragments', '_fragment_spreads', '_recursively_referenced_fragments', '_variable_usages', '_recursive_variable_usages'
34+
__slots__ = '_schema', '_ast', '_type_info', '_errors', '_fragments', '_fragment_spreads', '_recursively_referenced_fragments', '_variable_usages', '_recursive_variable_usages'
3535

3636
def __init__(self, schema, ast, type_info):
3737
self._schema = schema
3838
self._ast = ast
3939
self._type_info = type_info
40+
self._errors = []
4041
self._fragments = None
4142
self._fragment_spreads = {}
4243
self._recursively_referenced_fragments = {}
4344
self._variable_usages = {}
4445
self._recursive_variable_usages = {}
4546

47+
def report_error(self, error):
48+
self._errors.append(error)
49+
50+
def get_errors(self):
51+
return self._errors
52+
4653
def get_schema(self):
4754
return self._schema
4855

graphql/core/validation/rules/arguments_of_correct_type.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ def enter_Argument(self, node, key, parent, path, ancestors):
1010
if arg_def:
1111
errors = is_valid_literal_value(arg_def.type, node.value)
1212
if errors:
13-
return GraphQLError(
13+
self.context.report_error(GraphQLError(
1414
self.bad_value_message(node.name.value, arg_def.type,
1515
print_ast(node.value), errors),
1616
[node.value]
17-
)
17+
))
1818
return False
1919

2020
@staticmethod

graphql/core/validation/rules/default_values_of_correct_type.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,18 @@ def enter_VariableDefinition(self, node, key, parent, path, ancestors):
1212
type = self.context.get_input_type()
1313

1414
if isinstance(type, GraphQLNonNull) and default_value:
15-
return GraphQLError(
15+
self.context.report_error(GraphQLError(
1616
self.default_for_non_null_arg_message(name, type, type.of_type),
1717
[default_value]
18-
)
18+
))
1919

2020
if type and default_value:
2121
errors = is_valid_literal_value(type, default_value)
2222
if errors:
23-
return GraphQLError(
23+
self.context.report_error(GraphQLError(
2424
self.bad_value_for_default_arg_message(name, type, print_ast(default_value), errors),
2525
[default_value]
26-
)
26+
))
2727
return False
2828

2929
def enter_SelectionSet(self, node, key, parent, path, ancestors):

graphql/core/validation/rules/fields_on_correct_type.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ def enter_Field(self, node, key, parent, path, ancestors):
1010

1111
field_def = self.context.get_field_def()
1212
if not field_def:
13-
return GraphQLError(
13+
self.context.report_error(GraphQLError(
1414
self.undefined_field_message(node.name.value, type.name),
1515
[node]
16-
)
16+
))
1717

1818
@staticmethod
1919
def undefined_field_message(field_name, type):

graphql/core/validation/rules/fragments_on_composite_types.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,19 @@ def enter_InlineFragment(self, node, key, parent, path, ancestors):
99
type = self.context.get_type()
1010

1111
if node.type_condition and type and not is_composite_type(type):
12-
return GraphQLError(
12+
self.context.report_error(GraphQLError(
1313
self.inline_fragment_on_non_composite_error_message(print_ast(node.type_condition)),
1414
[node.type_condition]
15-
)
15+
))
1616

1717
def enter_FragmentDefinition(self, node, key, parent, path, ancestors):
1818
type = self.context.get_type()
1919

2020
if type and not is_composite_type(type):
21-
return GraphQLError(
21+
self.context.report_error(GraphQLError(
2222
self.fragment_on_non_composite_error_message(node.name.value, print_ast(node.type_condition)),
2323
[node.type_condition]
24-
)
24+
))
2525

2626
@staticmethod
2727
def inline_fragment_on_non_composite_error_message(type):

graphql/core/validation/rules/known_argument_names.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ def enter_Argument(self, node, key, parent, path, ancestors):
1717
if not field_arg_def:
1818
parent_type = self.context.get_parent_type()
1919
assert parent_type
20-
return GraphQLError(
20+
self.context.report_error(GraphQLError(
2121
self.unknown_arg_message(node.name.value, field_def.name, parent_type.name),
2222
[node]
23-
)
23+
))
2424

2525
elif isinstance(argument_of, ast.Directive):
2626
directive = self.context.get_directive()
@@ -30,10 +30,10 @@ def enter_Argument(self, node, key, parent, path, ancestors):
3030
directive_arg_def = next((arg for arg in directive.args if arg.name == node.name.value), None)
3131

3232
if not directive_arg_def:
33-
return GraphQLError(
33+
self.context.report_error(GraphQLError(
3434
self.unknown_directive_arg_message(node.name.value, directive.name),
3535
[node]
36-
)
36+
))
3737

3838
@staticmethod
3939
def unknown_arg_message(arg_name, field_name, type):

graphql/core/validation/rules/known_directives.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,31 +11,31 @@ def enter_Directive(self, node, key, parent, path, ancestors):
1111
), None)
1212

1313
if not directive_def:
14-
return GraphQLError(
14+
return self.context.report_error(GraphQLError(
1515
self.unknown_directive_message(node.name.value),
1616
[node]
17-
)
17+
))
1818

1919
applied_to = ancestors[-1]
2020

2121
if isinstance(applied_to, ast.OperationDefinition) and not directive_def.on_operation:
22-
return GraphQLError(
22+
self.context.report_error(GraphQLError(
2323
self.misplaced_directive_message(node.name.value, 'operation'),
2424
[node]
25-
)
25+
))
2626

27-
if isinstance(applied_to, ast.Field) and not directive_def.on_field:
28-
return GraphQLError(
27+
elif isinstance(applied_to, ast.Field) and not directive_def.on_field:
28+
self.context.report_error(GraphQLError(
2929
self.misplaced_directive_message(node.name.value, 'field'),
3030
[node]
31-
)
31+
))
3232

33-
if (isinstance(applied_to, (ast.FragmentSpread, ast.InlineFragment, ast.FragmentDefinition)) and
33+
elif (isinstance(applied_to, (ast.FragmentSpread, ast.InlineFragment, ast.FragmentDefinition)) and
3434
not directive_def.on_fragment):
35-
return GraphQLError(
35+
self.context.report_error(GraphQLError(
3636
self.misplaced_directive_message(node.name.value, 'fragment'),
3737
[node]
38-
)
38+
))
3939

4040
@staticmethod
4141
def unknown_directive_message(directive_name):

graphql/core/validation/rules/known_fragment_names.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ def enter_FragmentSpread(self, node, key, parent, path, ancestors):
88
fragment = self.context.get_fragment(fragment_name)
99

1010
if not fragment:
11-
return GraphQLError(
11+
self.context.report_error(GraphQLError(
1212
self.unknown_fragment_message(fragment_name),
1313
[node.name]
14-
)
14+
))
1515

1616
@staticmethod
1717
def unknown_fragment_message(fragment_name):

graphql/core/validation/rules/known_type_names.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ def enter_NamedType(self, node, *args):
88
type = self.context.get_schema().get_type(type_name)
99

1010
if not type:
11-
return GraphQLError(self.unknown_type_message(type_name), [node])
11+
self.context.report_error(GraphQLError(self.unknown_type_message(type_name), [node]))
1212

1313
@staticmethod
1414
def unknown_type_message(type):

graphql/core/validation/rules/lone_anonymous_operation.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def enter_Document(self, node, key, parent, path, ancestors):
1616

1717
def enter_OperationDefinition(self, node, key, parent, path, ancestors):
1818
if not node.name and self.operation_count > 1:
19-
return GraphQLError(self.anonymous_operation_not_alone_message(), [node])
19+
self.context.report_error(GraphQLError(self.anonymous_operation_not_alone_message(), [node]))
2020

2121
@staticmethod
2222
def anonymous_operation_not_alone_message():

graphql/core/validation/rules/no_fragment_cycles.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,6 @@ def __init__(self, context):
1414
self.spread_path = []
1515
self.spread_path_index_by_name = {}
1616

17-
def leave_Document(self, node, key, parent, path, ancestors):
18-
if self.errors:
19-
return self.errors
20-
2117
def enter_OperationDefinition(self, node, key, parent, path, ancestors):
2218
return False
2319

@@ -49,7 +45,7 @@ def detect_cycle_recursive(self, fragment):
4945
self.spread_path.pop()
5046
else:
5147
cycle_path = self.spread_path[cycle_index:]
52-
self.errors.append(GraphQLError(
48+
self.context.report_error(GraphQLError(
5349
self.cycle_error_message(
5450
spread_name,
5551
[s.name.value for s in cycle_path]

graphql/core/validation/rules/no_undefined_variables.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,15 @@ def enter_OperationDefinition(self, operation, key, parent, path, ancestors):
2323

2424
def leave_OperationDefinition(self, operation, key, parent, path, ancestors):
2525
usages = self.context.get_recursive_variable_usages(operation)
26-
errors = []
2726

2827
for variable_usage in usages:
2928
node = variable_usage.node
3029
var_name = node.name.value
3130
if var_name not in self.defined_variable_names:
32-
errors.append(GraphQLError(
31+
self.context.report_error(GraphQLError(
3332
self.undefined_var_message(var_name, operation.name and operation.name.value),
3433
[node, operation]
3534
))
3635

37-
if errors:
38-
return errors
39-
4036
def enter_VariableDefinition(self, node, key, parent, path, ancestors):
4137
self.defined_variable_names.add(node.variable.name.value)

graphql/core/validation/rules/no_unused_fragments.py

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,12 @@ def leave_Document(self, node, key, parent, path, ancestors):
2626
for fragment in fragments:
2727
fragment_names_used.add(fragment.name.value)
2828

29-
errors = [
30-
GraphQLError(
31-
self.unused_fragment_message(fragment_definition.name.value),
32-
[fragment_definition]
33-
)
34-
for fragment_definition in self.fragment_definitions
35-
if fragment_definition.name.value not in fragment_names_used
36-
]
37-
38-
if errors:
39-
return errors
29+
for fragment_definition in self.fragment_definitions:
30+
if fragment_definition.name.value not in fragment_names_used:
31+
self.context.report_error(GraphQLError(
32+
self.unused_fragment_message(fragment_definition.name.value),
33+
[fragment_definition]
34+
))
4035

4136
@staticmethod
4237
def unused_fragment_message(fragment_name):

graphql/core/validation/rules/no_unused_variables.py

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,12 @@ def leave_OperationDefinition(self, operation, key, parent, path, ancestors):
1919
for variable_usage in usages:
2020
variable_name_used.add(variable_usage.node.name.value)
2121

22-
errors = [
23-
GraphQLError(
24-
self.unused_variable_message(variable_definition.variable.name.value),
25-
[variable_definition]
26-
)
27-
for variable_definition in self.variable_definitions
28-
if variable_definition.variable.name.value not in variable_name_used
29-
]
30-
31-
if errors:
32-
return errors
22+
for variable_definition in self.variable_definitions:
23+
if variable_definition.variable.name.value not in variable_name_used:
24+
self.context.report_error(GraphQLError(
25+
self.unused_variable_message(variable_definition.variable.name.value),
26+
[variable_definition]
27+
))
3328

3429
def enter_VariableDefinition(self, node, key, parent, path, ancestors):
3530
self.variable_definitions.append(node)

graphql/core/validation/rules/overlapping_fields_can_be_merged.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,8 @@ def leave_SelectionSet(self, node, key, parent, path, ancestors):
123123

124124
conflicts = self.find_conflicts(field_map)
125125
if conflicts:
126-
return [
127-
GraphQLError(self.fields_conflict_message(reason_name, reason), list(fields1)+list(fields2)) for
128-
(reason_name, reason), fields1, fields2 in conflicts
129-
]
126+
for (reason_name, reason), fields1, fields2 in conflicts:
127+
self.context.report_error(GraphQLError(self.fields_conflict_message(reason_name, reason), list(fields1)+list(fields2)))
130128

131129
@staticmethod
132130
def same_type(type1, type2):

graphql/core/validation/rules/possible_fragment_spreads.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,20 @@ def enter_InlineFragment(self, node, key, parent, path, ancestors):
1313
frag_type = self.context.get_type()
1414
parent_type = self.context.get_parent_type()
1515
if frag_type and parent_type and not self.do_types_overlap(frag_type, parent_type):
16-
return GraphQLError(
16+
self.context.report_error(GraphQLError(
1717
self.type_incompatible_anon_spread_message(parent_type, frag_type),
1818
[node]
19-
)
19+
))
2020

2121
def enter_FragmentSpread(self, node, key, parent, path, ancestors):
2222
frag_name = node.name.value
2323
frag_type = self.get_fragment_type(self.context, frag_name)
2424
parent_type = self.context.get_parent_type()
2525
if frag_type and parent_type and not self.do_types_overlap(frag_type, parent_type):
26-
return GraphQLError(
26+
self.context.report_error(GraphQLError(
2727
self.type_incompatible_spread_message(frag_name, parent_type, frag_type),
2828
[node]
29-
)
29+
))
3030

3131
@staticmethod
3232
def get_fragment_type(context, name):

graphql/core/validation/rules/provided_non_null_arguments.py

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,41 +9,33 @@ def leave_Field(self, node, key, parent, path, ancestors):
99
if not field_def:
1010
return False
1111

12-
errors = []
1312
arg_asts = node.arguments or []
1413
arg_ast_map = {arg.name.value: arg for arg in arg_asts}
1514

1615
for arg_def in field_def.args:
1716
arg_ast = arg_ast_map.get(arg_def.name, None)
1817
if not arg_ast and isinstance(arg_def.type, GraphQLNonNull):
19-
errors.append(GraphQLError(
18+
self.context.report_error(GraphQLError(
2019
self.missing_field_arg_message(node.name.value, arg_def.name, arg_def.type),
2120
[node]
2221
))
2322

24-
if errors:
25-
return errors
26-
2723
def leave_Directive(self, node, key, parent, path, ancestors):
2824
directive_def = self.context.get_directive()
2925
if not directive_def:
3026
return False
3127

32-
errors = []
3328
arg_asts = node.arguments or []
3429
arg_ast_map = {arg.name.value: arg for arg in arg_asts}
3530

3631
for arg_def in directive_def.args:
3732
arg_ast = arg_ast_map.get(arg_def.name, None)
3833
if not arg_ast and isinstance(arg_def.type, GraphQLNonNull):
39-
errors.append(GraphQLError(
34+
self.context.report_error(GraphQLError(
4035
self.missing_directive_arg_message(node.name.value, arg_def.name, arg_def.type),
4136
[node]
4237
))
4338

44-
if errors:
45-
return errors
46-
4739
@staticmethod
4840
def missing_field_arg_message(name, arg_name, type):
4941
return 'Field "{}" argument "{}" of type "{}" is required but not provided.'.format(name, arg_name, type)

graphql/core/validation/rules/scalar_leafs.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,16 @@ def enter_Field(self, node, key, parent, path, ancestors):
1212

1313
if is_leaf_type(type):
1414
if node.selection_set:
15-
return GraphQLError(
15+
self.context.report_error(GraphQLError(
1616
self.no_subselection_allowed_message(node.name.value, type),
1717
[node.selection_set]
18-
)
18+
))
1919

2020
elif not node.selection_set:
21-
return GraphQLError(
21+
self.context.report_error(GraphQLError(
2222
self.required_subselection_message(node.name.value, type),
2323
[node]
24-
)
24+
))
2525

2626
@staticmethod
2727
def no_subselection_allowed_message(field, type):

0 commit comments

Comments
 (0)