Skip to content

Commit 8df5391

Browse files
tinnoubbakerman
authored andcommitted
Throws a MissingRootTypeException instead of branching.
To DRY I removed branching in the `executeOperation` method and throws an error whenever a query refers to a missing operation. This brings us a little closer to the reference implementation https://github.com/graphql/graphql-js/blob/master/src/execution/execute.js#L419.
1 parent e943f42 commit 8df5391

File tree

6 files changed

+69
-86
lines changed

6 files changed

+69
-86
lines changed

src/main/java/graphql/OperationNotSupportedError.java

Lines changed: 0 additions & 57 deletions
This file was deleted.

src/main/java/graphql/execution/Execution.java

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
import graphql.ExecutionResultImpl;
1414
import graphql.GraphQLError;
1515
import graphql.Internal;
16-
import graphql.OperationNotSupportedError;
1716
import graphql.execution.instrumentation.Instrumentation;
1817
import graphql.execution.instrumentation.InstrumentationContext;
1918
import graphql.execution.instrumentation.InstrumentationState;
@@ -106,24 +105,17 @@ private CompletableFuture<ExecutionResult> executeOperation(ExecutionContext exe
106105
InstrumentationContext<ExecutionResult> dataFetchCtx = instrumentation.beginDataFetch(dataFetchParameters);
107106

108107
OperationDefinition.Operation operation = operationDefinition.getOperation();
109-
GraphQLObjectType operationRootType = getOperationRootType(executionContext.getGraphQLSchema(), operation);
110-
111-
//
112-
// do we have a mutation operation root type. The spec says if we don't then mutations are not allowed to be executed
113-
//
114-
// for the record earlier code has asserted that we have a query type in the schema since the spec says this is
115-
// ALWAYS required
116-
if (operation == MUTATION && operationRootType == null) {
117-
OperationNotSupportedError mutationNotSupportedError = new OperationNotSupportedError("Schema is not configured for mutations.", operationDefinition.getSourceLocation());
118-
CompletableFuture<ExecutionResult> resultCompletableFuture = completedFuture(
119-
new ExecutionResultImpl(Collections.singletonList(mutationNotSupportedError)));
120-
executionDispatchCtx.onEnd(resultCompletableFuture, null);
121-
return resultCompletableFuture;
122-
} else if (operation == SUBSCRIPTION && operationRootType == null) {
123-
OperationNotSupportedError subscriptionNotSupportedError = new OperationNotSupportedError("Schema is not configured for subscriptions.", operationDefinition.getSourceLocation());
124-
CompletableFuture<ExecutionResult> resultCompletableFuture = completedFuture(new ExecutionResultImpl(Collections.singletonList(subscriptionNotSupportedError)));
125-
executionDispatchCtx.onEnd(resultCompletableFuture, null);
126-
return resultCompletableFuture;
108+
GraphQLObjectType operationRootType;
109+
110+
try {
111+
operationRootType = getOperationRootType(executionContext.getGraphQLSchema(), operationDefinition);
112+
} catch (RuntimeException rte) {
113+
if (rte instanceof GraphQLError) {
114+
CompletableFuture<ExecutionResult> resultCompletableFuture = completedFuture(new ExecutionResultImpl(Collections.singletonList((GraphQLError) rte)));
115+
executionDispatchCtx.onEnd(resultCompletableFuture, null);
116+
return resultCompletableFuture;
117+
}
118+
throw rte;
127119
}
128120

129121
FieldCollectorParameters collectorParameters = FieldCollectorParameters.newParameters()
@@ -178,13 +170,26 @@ private CompletableFuture<ExecutionResult> executeOperation(ExecutionContext exe
178170
return result;
179171
}
180172

181-
private GraphQLObjectType getOperationRootType(GraphQLSchema graphQLSchema, OperationDefinition.Operation operation) {
173+
private GraphQLObjectType getOperationRootType(GraphQLSchema graphQLSchema, OperationDefinition operationDefinition) {
174+
OperationDefinition.Operation operation = operationDefinition.getOperation();
182175
if (operation == MUTATION) {
183-
return graphQLSchema.getMutationType();
176+
GraphQLObjectType mutationType = graphQLSchema.getMutationType();
177+
if (mutationType == null) {
178+
throw new MissingRootTypeException("Schema is not configured for mutations.", operationDefinition.getSourceLocation());
179+
}
180+
return mutationType;
184181
} else if (operation == QUERY) {
185-
return graphQLSchema.getQueryType();
182+
GraphQLObjectType queryType = graphQLSchema.getQueryType();
183+
if (queryType == null) {
184+
throw new MissingRootTypeException("Schema does not define the required query root type.", operationDefinition.getSourceLocation());
185+
}
186+
return queryType;
186187
} else if (operation == SUBSCRIPTION) {
187-
return graphQLSchema.getSubscriptionType();
188+
GraphQLObjectType subscriptionType = graphQLSchema.getSubscriptionType();
189+
if (subscriptionType == null) {
190+
throw new MissingRootTypeException("Schema is not configured for subscriptions.", operationDefinition.getSourceLocation());
191+
}
192+
return subscriptionType;
188193
} else {
189194
return assertShouldNeverHappen("Unhandled case. An extra operation enum has been added without code support");
190195
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package graphql.execution;
2+
3+
import java.util.Collections;
4+
import java.util.List;
5+
6+
import graphql.ErrorType;
7+
import graphql.GraphQLError;
8+
import graphql.GraphQLException;
9+
import graphql.PublicApi;
10+
import graphql.language.SourceLocation;
11+
12+
/**
13+
* This is thrown if a query is attempting to perform an operation not defined in the GraphQL schema
14+
*/
15+
@PublicApi
16+
public class MissingRootTypeException extends GraphQLException implements GraphQLError {
17+
private List<SourceLocation> sourceLocations;
18+
19+
public MissingRootTypeException(String message, SourceLocation sourceLocation) {
20+
super(message);
21+
this.sourceLocations = sourceLocation == null ? null : Collections.singletonList(sourceLocation);
22+
}
23+
24+
@Override
25+
public List<SourceLocation> getLocations() {
26+
return sourceLocations;
27+
}
28+
29+
@Override
30+
public ErrorType getErrorType() {
31+
return ErrorType.OperationNotSupported;
32+
}
33+
}

src/test/groovy/example/http/ExecutionResultJSONTesting.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@
1313
import graphql.ExecutionResultImpl;
1414
import graphql.GraphQLError;
1515
import graphql.InvalidSyntaxError;
16-
import graphql.OperationNotSupportedError;
1716
import graphql.SerializationError;
1817
import graphql.execution.ExecutionPath;
1918
import graphql.execution.ExecutionTypeInfo;
19+
import graphql.execution.MissingRootTypeException;
2020
import graphql.execution.NonNullableFieldWasNullError;
2121
import graphql.execution.NonNullableFieldWasNullException;
2222
import graphql.introspection.Introspection;
@@ -71,7 +71,7 @@ private ExecutionResult createER() {
7171
List<GraphQLError> errors = new ArrayList<>();
7272

7373
errors.add(new ValidationError(ValidationErrorType.UnknownType, mkLocations(), "Test ValidationError"));
74-
errors.add(new OperationNotSupportedError("Mutations are not supported.", null));
74+
errors.add(new MissingRootTypeException("Mutations are not supported.", null));
7575
errors.add(new InvalidSyntaxError(mkLocations(), "Not good syntax m'kay"));
7676
errors.add(new NonNullableFieldWasNullError(new NonNullableFieldWasNullException(mkTypeInfo(), mkPath())));
7777
errors.add(new SerializationError(mkPath(), new CoercingSerializeException("Bad coercing")));

src/test/groovy/graphql/GraphQLErrorTest.groovy

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package graphql
22

33
import graphql.execution.ExecutionPath
44
import graphql.execution.ExecutionTypeInfo
5+
import graphql.execution.MissingRootTypeException
56
import graphql.execution.NonNullableFieldWasNullError
67
import graphql.execution.NonNullableFieldWasNullException
78
import graphql.introspection.Introspection
@@ -30,7 +31,7 @@ class GraphQLErrorTest extends Specification {
3031
message : "Validation error of type UnknownType: Test ValidationError",
3132
]
3233

33-
new OperationNotSupportedError("Mutations are not supported on this schema", null) |
34+
new MissingRootTypeException("Mutations are not supported on this schema", null) |
3435
[
3536
message: "Mutations are not supported on this schema",
3637
]

src/test/groovy/graphql/GraphQLTest.groovy

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import graphql.execution.ExecutionContext
77
import graphql.execution.ExecutionId
88
import graphql.execution.ExecutionIdProvider
99
import graphql.execution.ExecutionStrategyParameters
10+
import graphql.execution.MissingRootTypeException
1011
import graphql.execution.batched.BatchedExecutionStrategy
1112
import graphql.execution.instrumentation.Instrumentation
1213
import graphql.execution.instrumentation.NoOpInstrumentation
@@ -266,10 +267,10 @@ class GraphQLTest extends Specification {
266267

267268
then:
268269
result.errors.size() == 1
269-
result.errors[0].class == OperationNotSupportedError
270+
result.errors[0].class == MissingRootTypeException
270271
}
271272

272-
def "a subscription query against a schema that doesn't support subscriptions should result in a GraphQL error"() {
273+
def "#875 a subscription query against a schema that doesn't support subscriptions should result in a GraphQL error"() {
273274
given:
274275

275276
GraphQLSchema schema = newSchema().query(
@@ -283,7 +284,7 @@ class GraphQLTest extends Specification {
283284

284285
then:
285286
result.errors.size() == 1
286-
result.errors[0].class == OperationNotSupportedError
287+
result.errors[0].class == MissingRootTypeException
287288
}
288289

289290
def "query with int literal too large"() {

0 commit comments

Comments
 (0)