Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve NonNullableValueCoercedAsNullException message #2774

Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -43,6 +43,18 @@ public NonNullableValueCoercedAsNullException(VariableDefinition variableDefinit
this.path = path;
}

public NonNullableValueCoercedAsNullException(List<Object> path, GraphQLType graphQLType) {
super(format("Coerced Null value for NonNull type '%s'",
GraphQLTypeUtil.simplePrint(graphQLType)));
this.path = path;
}

public NonNullableValueCoercedAsNullException(VariableDefinition variableDefinition, String causeMessage) {
super(format("Variable '%s' has invalid value: %s",
variableDefinition.getName(), causeMessage));
this.sourceLocations = Collections.singletonList(variableDefinition.getSourceLocation());
}

public NonNullableValueCoercedAsNullException(String fieldName, List<Object> path, GraphQLType graphQLType) {
super(format("Field '%s' has coerced Null value for NonNull type '%s'",
fieldName, GraphQLTypeUtil.simplePrint(graphQLType)));
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/graphql/execution/ValuesResolver.java
Expand Up @@ -418,6 +418,8 @@ private Map<String, Object> externalValueToInternalValueForVariables(GraphQLSche
.cause(e.getCause())
.sourceLocation(variableDefinition.getSourceLocation())
.build();
} catch (NonNullableValueCoercedAsNullException e) {
throw new NonNullableValueCoercedAsNullException(variableDefinition, e.getMessage());
}
}

Expand Down Expand Up @@ -495,7 +497,7 @@ private Object externalValueToInternalValue(GraphqlFieldVisibility fieldVisibili
Object returnValue =
externalValueToInternalValue(fieldVisibility, unwrapOne(graphQLType), value);
if (returnValue == null) {
throw new NonNullableValueCoercedAsNullException("", emptyList(), graphQLType);
throw new NonNullableValueCoercedAsNullException(emptyList(), graphQLType);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem I see here is emptyList is not much better than "" - that is there is no real info available.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean its better than it was - but is it as good as it could be?

I guess we would have to "track" fields and types as we descending the ValueResolver to get excellent names in the exception

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am happy to merge this as progress over perfection

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather remove the emptyList() path

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have another PR - #2773 - that means this is less likely in terms of conditions where this will happen - still possible but less likely

}
return returnValue;
}
Expand Down
2 changes: 1 addition & 1 deletion src/test/groovy/graphql/Issue743.groovy
Expand Up @@ -28,6 +28,6 @@ class Issue743 extends Specification {
executionResult.data == null
executionResult.errors.size() == 1
executionResult.errors[0].errorType == ErrorType.ValidationError
executionResult.errors[0].message == "Variable 'isTrue' has coerced Null value for NonNull type 'Boolean!'"
executionResult.errors[0].message == "Variable 'isTrue' has invalid value: Variable 'isTrue' has coerced Null value for NonNull type 'Boolean!'"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variable 'isTrue' has invalid value:

Variable 'isTrue' has an invalid value:

}
}
6 changes: 3 additions & 3 deletions src/test/groovy/graphql/NullVariableCoercionTest.groovy
@@ -1,6 +1,6 @@
package graphql


import graphql.language.SourceLocation
import graphql.schema.DataFetcher
import graphql.schema.GraphQLObjectType
import graphql.schema.idl.RuntimeWiring
Expand Down Expand Up @@ -68,8 +68,8 @@ class NullVariableCoercionTest extends Specification {
varResult.data == null
varResult.errors.size() == 1
varResult.errors[0].errorType == ErrorType.ValidationError
varResult.errors[0].message == "Field 'baz' has coerced Null value for NonNull type 'String!'"
// varResult.errors[0].locations == [new SourceLocation(1, 11)]
varResult.errors[0].message == "Variable 'input' has invalid value: Field 'baz' has coerced Null value for NonNull type 'String!'"
varResult.errors[0].locations == [new SourceLocation(1, 11)]
}

def "can handle defaulting on complex input objects"() {
Expand Down
20 changes: 19 additions & 1 deletion src/test/groovy/graphql/execution/ValuesResolverTest.groovy
Expand Up @@ -495,7 +495,25 @@ class ValuesResolverTest extends Specification {

then:
def error = thrown(NonNullableValueCoercedAsNullException)
error.message == "Variable 'foo' has coerced Null value for NonNull type 'String!'"
error.message == "Variable 'foo' has invalid value: Variable 'foo' has coerced Null value for NonNull type 'String!'"
}

def "coerceVariableValues: if variableType is a list of Non-Nullable type, and element value is null, throw a query error"() {
given:
def schema = TestUtil.schemaWithInputType(list(nonNull(GraphQLString)))

def defaultValueForFoo = new ArrayValue([new StringValue("defaultValueForFoo")])
def type = new ListType(new NonNullType(new TypeName("String")))
VariableDefinition fooVarDef = new VariableDefinition("foo", type, defaultValueForFoo)

def variableValuesMap = ["foo": [null]]

when:
resolver.coerceVariableValues(schema, [fooVarDef], variableValuesMap)

then:
def error = thrown(NonNullableValueCoercedAsNullException)
error.message == "Variable 'foo' has invalid value: Coerced Null value for NonNull type 'String!'"
}

// Note: use NullValue defined in Field when it exists,
Expand Down