Skip to content

Commit 1cd5717

Browse files
committed
Preserving validation message for scalars and adding validation metadata in extensions (graphql-java#1
1 parent fb97f3e commit 1cd5717

19 files changed

Lines changed: 252 additions & 147 deletions

src/main/java/graphql/Scalars.java

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,8 @@
55
import graphql.language.FloatValue;
66
import graphql.language.IntValue;
77
import graphql.language.StringValue;
8-
import graphql.schema.Coercing;
9-
import graphql.schema.CoercingParseLiteralException;
10-
import graphql.schema.CoercingParseValueException;
11-
import graphql.schema.CoercingSerializeException;
12-
import graphql.schema.GraphQLScalarType;
8+
import graphql.schema.*;
9+
import graphql.validation.ValidationUtil;
1310

1411
import java.math.BigDecimal;
1512
import java.math.BigInteger;
@@ -248,9 +245,7 @@ public Boolean parseValue(Object input) {
248245
@Override
249246
public Boolean parseLiteral(Object input) {
250247
if (!(input instanceof BooleanValue)) {
251-
throw new CoercingParseLiteralException(
252-
"Expected AST type 'BooleanValue' but was '" + typeName(input) + "'."
253-
);
248+
throw new CoercingParseLiteralException(String.format("'%s' is not a valid Boolean", ValidationUtil.renderValue(input)));
254249
}
255250
return ((BooleanValue) input).isValue();
256251
}

src/main/java/graphql/schema/idl/errors/NonSDLDefinitionError.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ public class NonSDLDefinitionError extends BaseError {
88

99
public NonSDLDefinitionError(Definition definition) {
1010
super(definition, format("The schema definition text contains a non schema definition language (SDL) element '%s'",
11-
definition.getClass().getSimpleName(), lineCol(definition), lineCol(definition)));
11+
definition.getClass().getSimpleName()));
1212
}
1313
}

src/main/java/graphql/validation/AbstractRule.java

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,12 @@
11
package graphql.validation;
22

33

4+
import graphql.Internal;
5+
import graphql.language.*;
6+
47
import java.util.ArrayList;
58
import java.util.List;
6-
7-
import graphql.Internal;
8-
import graphql.language.Argument;
9-
import graphql.language.Directive;
10-
import graphql.language.Document;
11-
import graphql.language.Field;
12-
import graphql.language.FragmentDefinition;
13-
import graphql.language.FragmentSpread;
14-
import graphql.language.InlineFragment;
15-
import graphql.language.Node;
16-
import graphql.language.OperationDefinition;
17-
import graphql.language.SelectionSet;
18-
import graphql.language.SourceLocation;
19-
import graphql.language.TypeName;
20-
import graphql.language.VariableDefinition;
21-
import graphql.language.VariableReference;
9+
import java.util.Map;
2210

2311
@Internal
2412
public class AbstractRule {
@@ -65,6 +53,10 @@ public void addError(ValidationErrorType validationErrorType, SourceLocation loc
6553
validationErrorCollector.addError(new ValidationError(validationErrorType, location, description, getQueryPath()));
6654
}
6755

56+
public void addError(ValidationErrorType validationErrorType, SourceLocation location, String description, Map<String, Object> extensions) {
57+
validationErrorCollector.addError(new ValidationError(validationErrorType, location, description, getQueryPath(), extensions));
58+
}
59+
6860
public List<ValidationError> getErrors() {
6961
return validationErrorCollector.getErrors();
7062
}

src/main/java/graphql/validation/ArgumentValidationUtil.java

Lines changed: 47 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,21 @@
33
import graphql.language.Argument;
44
import graphql.language.ObjectField;
55
import graphql.language.Value;
6-
import graphql.schema.GraphQLEnumType;
7-
import graphql.schema.GraphQLInputObjectType;
8-
import graphql.schema.GraphQLScalarType;
9-
import graphql.schema.GraphQLType;
6+
import graphql.schema.*;
107

118
import java.util.ArrayList;
129
import java.util.List;
1310
import java.util.Set;
11+
import java.util.stream.Collectors;
1412

1513
public class ArgumentValidationUtil extends ValidationUtil {
1614

1715
private final List<String> argumentNames = new ArrayList<>();
18-
private Value argumentValue;
16+
private Value<?> argumentValue;
1917
private String errorMessage;
2018
private final List<Object> arguments = new ArrayList<>();
19+
private GraphQLType requiredType;
20+
private GraphQLType objectType;
2121

2222
private final String argumentName;
2323

@@ -28,66 +28,91 @@ public ArgumentValidationUtil(Argument argument) {
2828

2929
@Override
3030
protected void handleNullError(Value value, GraphQLType type) {
31-
errorMessage = "must not be null";
31+
errorMessage = "Value must not be null";
3232
argumentValue = value;
33+
setObjectField(type);
3334
}
3435

3536
@Override
36-
protected void handleScalarError(Value value, GraphQLScalarType type) {
37-
errorMessage = "is not a valid '%s'";
37+
protected void handleScalarError(Value value, GraphQLScalarType type, String message) {
38+
errorMessage = message;
3839
arguments.add(type.getName());
3940
argumentValue = value;
41+
setObjectField(type);
4042
}
4143

4244
@Override
4345
protected void handleEnumError(Value value, GraphQLEnumType type) {
4446
errorMessage = "is not a valid '%s'";
4547
arguments.add(type.getName());
4648
argumentValue = value;
49+
requiredType = type;
4750
}
4851

4952
@Override
5053
protected void handleNotObjectError(Value value, GraphQLInputObjectType type) {
51-
errorMessage = "must be an object type";
54+
errorMessage = "Value must be an object type";
55+
setObjectField(type);
5256
}
5357

5458
@Override
5559
protected void handleMissingFieldsError(Value value, GraphQLInputObjectType type, Set<String> missingFields) {
56-
errorMessage = "is missing required fields '%s'";
60+
errorMessage = String.format("Required fields are missing: '%s'", missingFields.stream().collect(Collectors.joining(", ", "[", "]")));
5761
arguments.add(missingFields);
62+
setObjectField(type);
5863
}
5964

6065
@Override
6166
protected void handleExtraFieldError(Value value, GraphQLInputObjectType type, ObjectField objectField) {
62-
errorMessage = "contains a field not in '%s': '%s'";
67+
errorMessage = String.format("Value contains a field not in '%s': '%s'", ValidationUtil.renderType(type), objectField.getName());
6368
arguments.add(type.getName());
6469
arguments.add(objectField.getName());
70+
setObjectField(type);
6571
}
6672

6773
@Override
6874
protected void handleFieldNotValidError(ObjectField objectField, GraphQLInputObjectType type) {
6975
argumentNames.add(0, objectField.getName());
76+
setObjectField(type);
7077
}
7178

7279
@Override
7380
protected void handleFieldNotValidError(Value value, GraphQLType type, int index) {
7481
argumentNames.add(0, String.format("[%s]", index));
82+
setObjectField(type);
83+
}
84+
85+
private void setObjectField(GraphQLType type) {
86+
objectType = type;
87+
if (requiredType == null) {
88+
requiredType = type;
89+
}
90+
}
91+
92+
public String getErrorMessage() {
93+
return errorMessage;
94+
}
95+
96+
public Value<?> getArgumentValue() {
97+
return argumentValue;
98+
}
99+
100+
public GraphQLType getRequiredType() {
101+
return requiredType;
75102
}
76103

77-
public String getMessage() {
104+
public GraphQLType getObjectType() {
105+
return objectType;
106+
}
107+
108+
public String renderArgument() {
78109
StringBuilder argument = new StringBuilder(argumentName);
79110
for (String name : argumentNames) {
80-
if (name.startsWith("[")) {
81-
argument.append(name);
82-
} else {
83-
argument.append(".").append(name);
111+
if (!name.startsWith("[")) {
112+
argument.append('.');
84113
}
114+
argument.append(name);
85115
}
86-
arguments.add(0, argument.toString());
87-
arguments.add(1, argumentValue);
88-
89-
String message = "argument '%s' with value '%s'" + " " + errorMessage;
90-
91-
return String.format(message, arguments.toArray());
116+
return argument.toString();
92117
}
93118
}

src/main/java/graphql/validation/ValidationError.java

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@
66
import graphql.GraphqlErrorHelper;
77
import graphql.language.SourceLocation;
88

9-
import java.util.ArrayList;
10-
import java.util.Collections;
11-
import java.util.List;
9+
import java.util.*;
1210
import java.util.stream.Collectors;
1311

1412
public class ValidationError implements GraphQLError {
@@ -18,6 +16,7 @@ public class ValidationError implements GraphQLError {
1816
private final String description;
1917
private final ValidationErrorType validationErrorType;
2018
private final List<String> queryPath;
19+
private final Map<String, Object> extensions;
2120

2221
public ValidationError(ValidationErrorType validationErrorType) {
2322
this(validationErrorType, (SourceLocation) null, null);
@@ -31,27 +30,37 @@ public ValidationError(ValidationErrorType validationErrorType, SourceLocation s
3130
this(validationErrorType, nullOrList(sourceLocation), description, queryPath);
3231
}
3332

33+
public ValidationError(ValidationErrorType validationErrorType, SourceLocation sourceLocation, String description, List<String> queryPath, Map<String, Object> extensions) {
34+
this(validationErrorType, nullOrList(sourceLocation), description, queryPath, extensions);
35+
}
36+
3437
public ValidationError(ValidationErrorType validationErrorType, List<SourceLocation> sourceLocations, String description) {
3538
this(validationErrorType, sourceLocations, description, null);
3639
}
3740

3841
public ValidationError(ValidationErrorType validationErrorType, List<SourceLocation> sourceLocations, String description, List<String> queryPath) {
42+
this(validationErrorType, sourceLocations, description, queryPath, Collections.emptyMap());
43+
}
44+
45+
public ValidationError(ValidationErrorType validationErrorType, List<SourceLocation> sourceLocations, String description, List<String> queryPath, Map<String, Object> extensions) {
3946
this.validationErrorType = validationErrorType;
4047
if (sourceLocations != null)
4148
this.locations.addAll(sourceLocations);
4249
this.description = description;
43-
this.message = mkMessage(validationErrorType, description, queryPath);
50+
this.message = description;
4451
this.queryPath = queryPath;
52+
53+
Map<String, Object> newExtensions = new LinkedHashMap<>(extensions);
54+
newExtensions.put("validationErrorType", validationErrorType.name());
55+
if (queryPath != null)
56+
newExtensions.put("queryPath", queryPath);
57+
this.extensions = Collections.unmodifiableMap(newExtensions);
4558
}
4659

4760
private static List<SourceLocation> nullOrList(SourceLocation sourceLocation) {
4861
return sourceLocation == null ? null : Collections.singletonList(sourceLocation);
4962
}
5063

51-
private String mkMessage(ValidationErrorType validationErrorType, String description, List<String> queryPath) {
52-
return String.format("Validation error of type %s: %s%s", validationErrorType, description, toPath(queryPath));
53-
}
54-
5564
private String toPath(List<String> queryPath) {
5665
if (queryPath == null) {
5766
return "";
@@ -86,6 +95,10 @@ public List<String> getQueryPath() {
8695
return queryPath;
8796
}
8897

98+
@Override
99+
public Map<String, Object> getExtensions() {
100+
return extensions;
101+
}
89102

90103
@Override
91104
public String toString() {

0 commit comments

Comments
 (0)