Skip to content

Commit 5f62bf0

Browse files
committed
better exceptions for incorrect types
1 parent 96578f4 commit 5f62bf0

File tree

4 files changed

+95
-4
lines changed

4 files changed

+95
-4
lines changed

src/main/java/graphql/schema/idl/SchemaGenerator.java

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import graphql.language.Type;
2323
import graphql.language.TypeDefinition;
2424
import graphql.language.TypeExtensionDefinition;
25-
import graphql.language.TypeName;
2625
import graphql.language.UnionTypeDefinition;
2726
import graphql.language.Value;
2827
import graphql.schema.DataFetcher;
@@ -42,6 +41,8 @@
4241
import graphql.schema.PropertyDataFetcher;
4342
import graphql.schema.TypeResolver;
4443
import graphql.schema.TypeResolverProxy;
44+
import graphql.schema.idl.errors.NotAnInputTypeError;
45+
import graphql.schema.idl.errors.NotAnOutputTypeError;
4546
import graphql.schema.idl.errors.SchemaProblem;
4647

4748
import java.util.Collections;
@@ -135,7 +136,9 @@ public SchemaGenerator() {
135136
*
136137
* @param typeRegistry this can be obtained via {@link SchemaCompiler#compile(String)}
137138
* @param wiring this can be built using {@link RuntimeWiring#newRuntimeWiring()}
139+
*
138140
* @return an executable schema
141+
*
139142
* @throws SchemaProblem if there are problems in assembling a schema such as missing type resolvers or no operations defined
140143
*/
141144
public GraphQLSchema makeExecutableSchema(TypeDefinitionRegistry typeRegistry, RuntimeWiring wiring) throws SchemaProblem {
@@ -184,6 +187,7 @@ private GraphQLObjectType buildOperation(BuildContext buildCtx, OperationTypeDef
184187
*
185188
* @param buildCtx the context we need to work out what we are doing
186189
* @param rawType the type to be built
190+
*
187191
* @return an output type
188192
*/
189193
@SuppressWarnings("unchecked")
@@ -213,8 +217,11 @@ private <T extends GraphQLOutputType> T buildOutputType(BuildContext buildCtx, T
213217
outputType = buildUnionType(buildCtx, (UnionTypeDefinition) typeDefinition);
214218
} else if (typeDefinition instanceof EnumTypeDefinition) {
215219
outputType = buildEnumType((EnumTypeDefinition) typeDefinition);
216-
} else {
220+
} else if (typeDefinition instanceof ScalarTypeDefinition){
217221
outputType = buildScalar(buildCtx, (ScalarTypeDefinition) typeDefinition);
222+
} else {
223+
// typeDefinition is not a valid output type
224+
throw new NotAnOutputTypeError(typeDefinition);
218225
}
219226

220227
buildCtx.put(outputType);
@@ -243,8 +250,11 @@ private GraphQLInputType buildInputType(BuildContext buildCtx, Type rawType) {
243250
inputType = buildInputObjectType(buildCtx, (InputObjectTypeDefinition) typeDefinition);
244251
} else if (typeDefinition instanceof EnumTypeDefinition) {
245252
inputType = buildEnumType((EnumTypeDefinition) typeDefinition);
246-
} else {
253+
} else if (typeDefinition instanceof ScalarTypeDefinition){
247254
inputType = buildScalar(buildCtx, (ScalarTypeDefinition) typeDefinition);
255+
} else {
256+
// typeDefinition is not a valid InputType
257+
throw new NotAnInputTypeError(typeDefinition);
248258
}
249259

250260
buildCtx.put(inputType);
@@ -331,7 +341,9 @@ private GraphQLUnionType buildUnionType(BuildContext buildCtx, UnionTypeDefiniti
331341
builder.typeResolver(getTypeResolver(buildCtx, typeDefinition.getName()));
332342

333343
typeDefinition.getMemberTypes().forEach(mt -> {
334-
builder.possibleType(new GraphQLTypeReference(((TypeName) mt).getName()));
344+
TypeDefinition memberTypeDef = buildCtx.getTypeDefinition(mt);
345+
GraphQLObjectType objectType = buildObjectType(buildCtx, (ObjectTypeDefinition) memberTypeDef);
346+
builder.possibleType(objectType);
335347
});
336348
return builder.build();
337349
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package graphql.schema.idl.errors;
2+
3+
import graphql.language.TypeDefinition;
4+
5+
import static java.lang.String.format;
6+
7+
public class NotAnInputTypeError extends BaseError {
8+
9+
public NotAnInputTypeError(TypeDefinition typeDefinition) {
10+
super(typeDefinition, format("The %s type is used as an InputType, but is not declared as one", typeDefinition.getName()));
11+
}
12+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package graphql.schema.idl.errors;
2+
3+
import graphql.language.TypeDefinition;
4+
5+
import static java.lang.String.format;
6+
7+
public class NotAnOutputTypeError extends BaseError {
8+
9+
public NotAnOutputTypeError(TypeDefinition typeDefinition) {
10+
super(typeDefinition, format("The %s type is used as an OutputType, but is not declared as one", typeDefinition.getName()));
11+
}
12+
}

src/test/groovy/graphql/schema/idl/SchemaGeneratorTest.groovy

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package graphql.schema.idl
22

33
import graphql.TypeResolutionEnvironment
44
import graphql.schema.*
5+
import graphql.schema.idl.errors.NotAnInputTypeError
6+
import graphql.schema.idl.errors.NotAnOutputTypeError
57
import spock.lang.Specification
68

79
import java.util.function.UnaryOperator
@@ -479,8 +481,61 @@ class SchemaGeneratorTest extends Specification {
479481

480482
type.interfaces.size() == 1
481483
type.interfaces[0].name == "Character"
484+
}
485+
486+
def "Type used as inputType should throw appropriate error #425"() {
487+
when:
488+
def spec = """
489+
schema {
490+
query: Query
491+
}
492+
493+
type Query {
494+
findCharacter(character: CharacterInput!): Boolean
495+
}
496+
497+
# CharacterInput must be an input, but is a type
498+
type CharacterInput {
499+
firstName: String
500+
lastName: String
501+
family: Boolean
502+
}
503+
"""
504+
def wiring = RuntimeWiring.newRuntimeWiring()
505+
.build()
506+
507+
generateSchema(spec, wiring)
482508

509+
then:
510+
def err = thrown(NotAnInputTypeError.class)
511+
err.message == "The CharacterInput type is used as an InputType, but is not declared as one"
512+
}
513+
514+
def "InputType used as type should throw appropriate error #425"() {
515+
when:
516+
def spec = """
517+
schema {
518+
query: Query
519+
}
520+
521+
type Query {
522+
findCharacter: CharacterInput
523+
}
524+
525+
# CharacterInput must be an input, but is a type
526+
input CharacterInput {
527+
firstName: String
528+
lastName: String
529+
family: Boolean
530+
}
531+
"""
532+
def wiring = RuntimeWiring.newRuntimeWiring()
533+
.build()
483534

535+
generateSchema(spec, wiring)
484536

537+
then:
538+
def err = thrown(NotAnOutputTypeError.class)
539+
err.message == "The CharacterInput type is used as an OutputType, but is not declared as one"
485540
}
486541
}

0 commit comments

Comments
 (0)