Skip to content

Commit 7923cdb

Browse files
committed
Extract error handling logic into interface to make it extensible (fixes #30, fixes #32)
1 parent 8ec23f2 commit 7923cdb

File tree

5 files changed

+121
-33
lines changed

5 files changed

+121
-33
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/**
2+
* Copyright 2016 Yurii Rashkovskii
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
*/
15+
package graphql.servlet;
16+
17+
import graphql.ExceptionWhileDataFetching;
18+
import graphql.GraphQLError;
19+
import org.slf4j.Logger;
20+
import org.slf4j.LoggerFactory;
21+
22+
import java.util.List;
23+
import java.util.stream.Collectors;
24+
25+
/**
26+
* @author Andrew Potter
27+
*/
28+
public class DefaultGraphQLErrorHandler implements GraphQLErrorHandler {
29+
30+
public static final Logger log = LoggerFactory.getLogger(DefaultGraphQLErrorHandler.class);
31+
32+
@Override
33+
public List<GraphQLError> processErrors(List<GraphQLError> errors) {
34+
final List<GraphQLError> clientErrors = filterGraphQLErrors(errors);
35+
if (clientErrors.size() < errors.size()) {
36+
37+
// Some errors were filtered out to hide implementation - put a generic error in place.
38+
clientErrors.add(new GenericGraphQLError("Internal Server Error(s) while executing query"));
39+
40+
errors.stream()
41+
.filter(error -> !isClientError(error))
42+
.forEach(error -> log.error("Error executing query ({}): {}", error.getClass().getSimpleName(), error.getMessage()));
43+
}
44+
45+
return clientErrors;
46+
}
47+
48+
protected List<GraphQLError> filterGraphQLErrors(List<GraphQLError> errors) {
49+
return errors.stream()
50+
.filter(this::isClientError)
51+
.collect(Collectors.toList());
52+
}
53+
54+
protected boolean isClientError(GraphQLError error) {
55+
return !(error instanceof ExceptionWhileDataFetching);
56+
}
57+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/**
2+
* Copyright 2016 Yurii Rashkovskii
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
*/
15+
package graphql.servlet;
16+
17+
import graphql.GraphQLError;
18+
19+
import java.util.List;
20+
21+
/**
22+
* @author Andrew Potter
23+
*/
24+
public interface GraphQLErrorHandler {
25+
default boolean errorsPresent(List<GraphQLError> errors) {
26+
return errors != null && !errors.isEmpty();
27+
}
28+
29+
List<GraphQLError> processErrors(List<GraphQLError> errors);
30+
}

src/main/java/graphql/servlet/GraphQLServlet.java

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ public abstract class GraphQLServlet extends HttpServlet implements Servlet, Gra
7878
protected abstract ExecutionStrategyProvider getExecutionStrategyProvider();
7979
protected abstract Instrumentation getInstrumentation();
8080
protected abstract Map<String, Object> transformVariables(GraphQLSchema schema, String query, Map<String, Object> variables);
81+
protected abstract GraphQLErrorHandler getGraphQLErrorHandler();
8182

8283
private final List<GraphQLServletListener> listeners;
8384
private final ServletFileUpload fileUpload;
@@ -286,7 +287,7 @@ private void query(String query, String operationName, Map<String, Object> varia
286287
resp.setStatus(STATUS_OK);
287288
resp.getWriter().write(response);
288289

289-
if(errorsPresent(errors)) {
290+
if(getGraphQLErrorHandler().errorsPresent(errors)) {
290291
runCallbacks(operationCallbacks, c -> c.onError(context, operationName, query, variables, data, errors));
291292
} else {
292293
runCallbacks(operationCallbacks, c -> c.onSuccess(context, operationName, query, variables, data));
@@ -301,38 +302,13 @@ private Map<String, Object> createResultFromDataAndErrors(Object data, List<Grap
301302
final Map<String, Object> result = new HashMap<>();
302303
result.put("data", data);
303304

304-
if (errorsPresent(errors)) {
305-
final List<GraphQLError> clientErrors = filterGraphQLErrors(errors);
306-
if (clientErrors.size() < errors.size()) {
307-
// Some errors were filtered out to hide implementation - put a generic error in place.
308-
clientErrors.add(new GenericGraphQLError("Internal Server Error(s) while executing query"));
309-
310-
errors.stream()
311-
.filter(error -> !isClientError(error))
312-
.forEach(error -> {
313-
log.error("Error executing query ({}): {}", error.getClass().getSimpleName(), error.getMessage());
314-
});
315-
}
316-
result.put("errors", clientErrors);
305+
if (getGraphQLErrorHandler().errorsPresent(errors)) {
306+
result.put("errors", getGraphQLErrorHandler().processErrors(errors));
317307
}
318308

319309
return result;
320310
}
321311

322-
private boolean errorsPresent(List<GraphQLError> errors) {
323-
return errors != null && !errors.isEmpty();
324-
}
325-
326-
protected List<GraphQLError> filterGraphQLErrors(List<GraphQLError> errors) {
327-
return errors.stream()
328-
.filter(this::isClientError)
329-
.collect(Collectors.toList());
330-
}
331-
332-
protected boolean isClientError(GraphQLError error) {
333-
return error instanceof InvalidSyntaxError || error instanceof ValidationError;
334-
}
335-
336312
private <R> List<R> runListeners(Function<? super GraphQLServletListener, R> action) {
337313
if (listeners == null) {
338314
return Collections.emptyList();

src/main/java/graphql/servlet/OsgiGraphQLServlet.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ public class OsgiGraphQLServlet extends GraphQLServlet {
4848
private GraphQLContextBuilder contextBuilder = new DefaultGraphQLContextBuilder();
4949
private ExecutionStrategyProvider executionStrategyProvider = new EnhancedExecutionStrategyProvider();
5050
private InstrumentationProvider instrumentationProvider = new NoOpInstrumentationProvider();
51+
private GraphQLErrorHandler errorHandler = new DefaultGraphQLErrorHandler();
5152

5253
private GraphQLSchemaProvider schemaProvider;
5354

@@ -174,6 +175,14 @@ public void unsetInstrumentationProvider(InstrumentationProvider provider) {
174175
instrumentationProvider = new NoOpInstrumentationProvider();
175176
}
176177

178+
@Reference(cardinality = ReferenceCardinality.OPTIONAL)
179+
public void setErrorHandler(GraphQLErrorHandler errorHandler) {
180+
this.errorHandler = errorHandler;
181+
}
182+
public void unsetErrorHandler(GraphQLErrorHandler errorHandler) {
183+
this.errorHandler = new DefaultGraphQLErrorHandler();
184+
}
185+
177186
@Override
178187
protected GraphQLSchemaProvider getSchemaProvider() {
179188
return schemaProvider;
@@ -197,4 +206,9 @@ protected Instrumentation getInstrumentation() {
197206
protected Map<String, Object> transformVariables(GraphQLSchema schema, String query, Map<String, Object> variables) {
198207
return new GraphQLVariables(schema, query, variables);
199208
}
209+
210+
@Override
211+
protected GraphQLErrorHandler getGraphQLErrorHandler() {
212+
return errorHandler;
213+
}
200214
}

src/main/java/graphql/servlet/SimpleGraphQLServlet.java

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
package graphql.servlet;
1616

1717
import graphql.execution.ExecutionStrategy;
18-
import graphql.execution.SimpleExecutionStrategy;
1918
import graphql.execution.instrumentation.Instrumentation;
2019
import graphql.execution.instrumentation.NoOpInstrumentation;
2120
import graphql.schema.GraphQLSchema;
@@ -40,14 +39,14 @@ public SimpleGraphQLServlet(GraphQLSchema schema, ExecutionStrategy executionStr
4039
}
4140

4241
public SimpleGraphQLServlet(GraphQLSchema schema, ExecutionStrategyProvider executionStrategyProvider) {
43-
this(schema, executionStrategyProvider, null, null);
42+
this(schema, executionStrategyProvider, null, null, null);
4443
}
4544

46-
public SimpleGraphQLServlet(final GraphQLSchema schema, ExecutionStrategyProvider executionStrategyProvider, List<GraphQLServletListener> listeners, Instrumentation instrumentation) {
47-
this(new DefaultGraphQLSchemaProvider(schema), executionStrategyProvider, listeners, instrumentation);
45+
public SimpleGraphQLServlet(final GraphQLSchema schema, ExecutionStrategyProvider executionStrategyProvider, List<GraphQLServletListener> listeners, Instrumentation instrumentation, GraphQLErrorHandler errorHandler) {
46+
this(new DefaultGraphQLSchemaProvider(schema), executionStrategyProvider, listeners, instrumentation, errorHandler);
4847
}
4948

50-
public SimpleGraphQLServlet(GraphQLSchemaProvider schemaProvider, ExecutionStrategyProvider executionStrategyProvider, List<GraphQLServletListener> listeners, Instrumentation instrumentation) {
49+
public SimpleGraphQLServlet(GraphQLSchemaProvider schemaProvider, ExecutionStrategyProvider executionStrategyProvider, List<GraphQLServletListener> listeners, Instrumentation instrumentation, GraphQLErrorHandler errorHandler) {
5150
super(listeners, null);
5251

5352
this.schemaProvider = schemaProvider;
@@ -58,11 +57,18 @@ public SimpleGraphQLServlet(GraphQLSchemaProvider schemaProvider, ExecutionStrat
5857
} else {
5958
this.instrumentation = instrumentation;
6059
}
60+
61+
if(errorHandler == null) {
62+
this.errorHandler = new DefaultGraphQLErrorHandler();
63+
} else {
64+
this.errorHandler = errorHandler;
65+
}
6166
}
6267

6368
private final GraphQLSchemaProvider schemaProvider;
6469
private final ExecutionStrategyProvider executionStrategyProvider;
6570
private final Instrumentation instrumentation;
71+
private final GraphQLErrorHandler errorHandler;
6672

6773
@Override
6874
protected GraphQLSchemaProvider getSchemaProvider() {
@@ -88,4 +94,9 @@ protected Instrumentation getInstrumentation() {
8894
protected Map<String, Object> transformVariables(GraphQLSchema schema, String query, Map<String, Object> variables) {
8995
return variables;
9096
}
97+
98+
@Override
99+
protected GraphQLErrorHandler getGraphQLErrorHandler() {
100+
return errorHandler;
101+
}
91102
}

0 commit comments

Comments
 (0)