Skip to content

Commit db24c8f

Browse files
committed
Replace GraphQLError with GraphQlResponseError
This allows exposing additional conveniences for inspecting errors. See gh-10
1 parent 9613518 commit db24c8f

File tree

15 files changed

+297
-213
lines changed

15 files changed

+297
-213
lines changed

spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/AbstractDirectTransport.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@
1919
import java.util.List;
2020

2121
import graphql.ExecutionResult;
22-
import graphql.GraphQLError;
2322
import org.reactivestreams.Publisher;
2423
import reactor.core.publisher.Flux;
2524
import reactor.core.publisher.Mono;
2625

2726
import org.springframework.graphql.GraphQlRequest;
2827
import org.springframework.graphql.GraphQlResponse;
28+
import org.springframework.graphql.GraphQlResponseError;
2929
import org.springframework.graphql.RequestOutput;
3030
import org.springframework.graphql.client.GraphQlTransport;
3131
import org.springframework.test.util.AssertionErrors;
@@ -58,7 +58,7 @@ public Flux<GraphQlResponse> executeSubscription(GraphQlRequest request) {
5858
Object data = output.getData();
5959
AssertionErrors.assertTrue("Not a Publisher: " + data, data instanceof Publisher);
6060

61-
List<GraphQLError> errors = output.getErrors();
61+
List<GraphQlResponseError> errors = output.getErrors();
6262
AssertionErrors.assertTrue("Subscription errors: " + errors, CollectionUtils.isEmpty(errors));
6363

6464
return Flux.from((Publisher<ExecutionResult>) data)

spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/AbstractGraphQlTesterBuilder.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
import com.jayway.jsonpath.spi.json.JacksonJsonProvider;
2525
import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider;
2626
import com.jayway.jsonpath.spi.mapper.MappingProvider;
27-
import graphql.GraphQLError;
2827

28+
import org.springframework.graphql.GraphQlResponseError;
2929
import org.springframework.graphql.client.AbstractGraphQlClientBuilder;
3030
import org.springframework.graphql.client.GraphQlTransport;
3131
import org.springframework.graphql.support.CachingDocumentSource;
@@ -57,7 +57,7 @@ public abstract class AbstractGraphQlTesterBuilder<B extends AbstractGraphQlTest
5757

5858

5959
@Nullable
60-
private Predicate<GraphQLError> errorFilter;
60+
private Predicate<GraphQlResponseError> errorFilter;
6161

6262
private DocumentSource documentSource = new CachingDocumentSource(new ResourceDocumentSource());
6363

@@ -67,7 +67,7 @@ public abstract class AbstractGraphQlTesterBuilder<B extends AbstractGraphQlTest
6767

6868

6969
@Override
70-
public B errorFilter(Predicate<GraphQLError> predicate) {
70+
public B errorFilter(Predicate<GraphQlResponseError> predicate) {
7171
this.errorFilter = (this.errorFilter != null ? errorFilter.and(predicate) : predicate);
7272
return self();
7373
}

spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultGraphQlTester.java

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,12 @@
3131
import com.jayway.jsonpath.DocumentContext;
3232
import com.jayway.jsonpath.JsonPath;
3333
import com.jayway.jsonpath.TypeRef;
34-
import graphql.GraphQLError;
3534

3635
import org.springframework.core.ParameterizedTypeReference;
3736
import org.springframework.core.ResolvableType;
3837
import org.springframework.graphql.GraphQlRequest;
3938
import org.springframework.graphql.GraphQlResponse;
39+
import org.springframework.graphql.GraphQlResponseError;
4040
import org.springframework.graphql.client.GraphQlTransport;
4141
import org.springframework.graphql.support.DocumentSource;
4242
import org.springframework.lang.Nullable;
@@ -61,7 +61,7 @@ final class DefaultGraphQlTester implements GraphQlTester {
6161
private final GraphQlTransport transport;
6262

6363
@Nullable
64-
private final Predicate<GraphQLError> errorFilter;
64+
private final Predicate<GraphQlResponseError> errorFilter;
6565

6666
private final Configuration jsonPathConfig;
6767

@@ -76,7 +76,7 @@ final class DefaultGraphQlTester implements GraphQlTester {
7676
* Package private constructor for use from {@link AbstractGraphQlTesterBuilder}.
7777
*/
7878
DefaultGraphQlTester(
79-
GraphQlTransport transport, @Nullable Predicate<GraphQLError> errorFilter,
79+
GraphQlTransport transport, @Nullable Predicate<GraphQlResponseError> errorFilter,
8080
Configuration jsonPathConfig, DocumentSource documentSource, Duration timeout,
8181
Consumer<AbstractGraphQlTesterBuilder<?>> builderInitializer) {
8282

@@ -209,15 +209,15 @@ private final static class ResponseDelegate {
209209

210210
private final Supplier<String> jsonContent;
211211

212-
private final List<GraphQLError> errors;
212+
private final List<GraphQlResponseError> errors;
213213

214-
private final List<GraphQLError> unexpectedErrors;
214+
private final List<GraphQlResponseError> unexpectedErrors;
215215

216216
private final Consumer<Runnable> assertDecorator;
217217

218218

219219
private ResponseDelegate(
220-
GraphQlResponse response, @Nullable Predicate<GraphQLError> errorFilter,
220+
GraphQlResponse response, @Nullable Predicate<GraphQlResponseError> errorFilter,
221221
Consumer<Runnable> assertDecorator, Configuration jsonPathConfig) {
222222

223223
this.jsonDoc = JsonPath.parse(response.toMap(), jsonPathConfig);
@@ -253,9 +253,9 @@ void doAssert(Runnable task) {
253253
this.assertDecorator.accept(task);
254254
}
255255

256-
boolean filterErrors(Predicate<GraphQLError> predicate) {
256+
boolean filterErrors(Predicate<GraphQlResponseError> predicate) {
257257
boolean filtered = false;
258-
for (GraphQLError error : this.errors) {
258+
for (GraphQlResponseError error : this.errors) {
259259
if (predicate.test(error)) {
260260
this.unexpectedErrors.remove(error);
261261
filtered = true;
@@ -264,12 +264,12 @@ boolean filterErrors(Predicate<GraphQLError> predicate) {
264264
return filtered;
265265
}
266266

267-
void expectErrors(Predicate<GraphQLError> predicate) {
267+
void expectErrors(Predicate<GraphQlResponseError> predicate) {
268268
boolean filtered = filterErrors(predicate);
269269
this.assertDecorator.accept(() -> AssertionErrors.assertTrue("No matching errors.", filtered));
270270
}
271271

272-
void consumeErrors(Consumer<List<GraphQLError>> consumer) {
272+
void consumeErrors(Consumer<List<GraphQlResponseError>> consumer) {
273273
filterErrors(error -> true);
274274
consumer.accept(this.errors);
275275
}
@@ -293,7 +293,7 @@ private static final class DefaultResponse implements Response, Errors {
293293
private final ResponseDelegate delegate;
294294

295295
private DefaultResponse(
296-
GraphQlResponse response, @Nullable Predicate<GraphQLError> errorFilter,
296+
GraphQlResponse response, @Nullable Predicate<GraphQlResponseError> errorFilter,
297297
Consumer<Runnable> assertDecorator, Configuration jsonPathConfig) {
298298

299299
this.delegate = new ResponseDelegate(response, errorFilter, assertDecorator, jsonPathConfig);
@@ -311,13 +311,13 @@ public Errors errors() {
311311
}
312312

313313
@Override
314-
public Errors filter(Predicate<GraphQLError> predicate) {
314+
public Errors filter(Predicate<GraphQlResponseError> predicate) {
315315
this.delegate.filterErrors(predicate);
316316
return this;
317317
}
318318

319319
@Override
320-
public Errors expect(Predicate<GraphQLError> predicate) {
320+
public Errors expect(Predicate<GraphQlResponseError> predicate) {
321321
this.delegate.expectErrors(predicate);
322322
return this;
323323
}
@@ -329,7 +329,7 @@ public Traversable verify() {
329329
}
330330

331331
@Override
332-
public Traversable satisfy(Consumer<List<GraphQLError>> consumer) {
332+
public Traversable satisfy(Consumer<List<GraphQlResponseError>> consumer) {
333333
this.delegate.consumeErrors(consumer);
334334
return this;
335335
}

spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/GraphQlTester.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@
2121
import java.util.function.Consumer;
2222
import java.util.function.Predicate;
2323

24-
import graphql.GraphQLError;
2524
import reactor.core.publisher.Flux;
2625

2726
import org.springframework.core.ParameterizedTypeReference;
27+
import org.springframework.graphql.GraphQlResponseError;
2828
import org.springframework.graphql.client.GraphQlTransport;
2929
import org.springframework.graphql.support.DocumentSource;
3030
import org.springframework.graphql.support.ResourceDocumentSource;
@@ -103,7 +103,7 @@ interface Builder<B extends Builder<B>> {
103103
* @param predicate the error filter to add
104104
* @return the same builder instance
105105
*/
106-
B errorFilter(Predicate<GraphQLError> predicate);
106+
B errorFilter(Predicate<GraphQlResponseError> predicate);
107107

108108
/**
109109
* Configure a {@link DocumentSource} for use with
@@ -448,7 +448,7 @@ interface Errors {
448448
* @param errorPredicate the error filter to add
449449
* @return the same spec to add more filters before {@link #verify()}
450450
*/
451-
Errors filter(Predicate<GraphQLError> errorPredicate);
451+
Errors filter(Predicate<GraphQlResponseError> errorPredicate);
452452

453453
/**
454454
* Use this to declare errors that are expected.
@@ -461,7 +461,7 @@ interface Errors {
461461
* @param errorPredicate the predicate for the expected error
462462
* @return the same spec to add more filters or expected errors
463463
*/
464-
Errors expect(Predicate<GraphQLError> errorPredicate);
464+
Errors expect(Predicate<GraphQlResponseError> errorPredicate);
465465

466466
/**
467467
* Verify there are either no errors or that there no unexpected errors that have
@@ -477,7 +477,7 @@ interface Errors {
477477
* @param errorsConsumer to inspect errors with
478478
* @return a spec to switch to a data path
479479
*/
480-
Traversable satisfy(Consumer<List<GraphQLError>> errorsConsumer);
480+
Traversable satisfy(Consumer<List<GraphQlResponseError>> errorsConsumer);
481481

482482
}
483483

spring-graphql/src/main/java/org/springframework/graphql/GraphQlResponse.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@
2020
import java.util.List;
2121
import java.util.Map;
2222

23-
import graphql.GraphQLError;
24-
2523
import org.springframework.lang.Nullable;
2624

2725
/**
@@ -61,7 +59,7 @@ public interface GraphQlResponse {
6159
* response is not {@link #isValid() valid} and/or "field errors" for a
6260
* partial response.
6361
*/
64-
List<GraphQLError> getErrors();
62+
List<GraphQlResponseError> getErrors();
6563

6664
/**
6765
* Return implementor specific, protocol extensions, if any.
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package org.springframework.graphql;
2+
3+
import java.util.List;
4+
import java.util.Map;
5+
6+
import graphql.ErrorClassification;
7+
import graphql.language.SourceLocation;
8+
9+
import org.springframework.lang.Nullable;
10+
11+
/**
12+
* Represents a GraphQL response error.
13+
*
14+
* @author Rossen Stoyanchev
15+
* @since 1.0
16+
*/
17+
public interface GraphQlResponseError {
18+
19+
/**
20+
* Return the message with a description of the error intended for the
21+
* developer as a guide to understand and correct the error.
22+
*/
23+
@Nullable
24+
String getMessage();
25+
26+
/**
27+
* Return a list of locations in the GraphQL document, if the error can be
28+
* associated to a particular point in the document. Each location has a
29+
* line and a column, both positive, starting from 1 and describing the
30+
* beginning of an associated syntax element.
31+
*/
32+
List<SourceLocation> getLocations();
33+
34+
/**
35+
* Return a classification for the error that is specific to GraphQL Java.
36+
* This is serialized under {@link #getExtensions() "extensions"} in the
37+
* response map.
38+
* @see graphql.ErrorType
39+
* @see org.springframework.graphql.execution.ErrorType
40+
*/
41+
@Nullable
42+
ErrorClassification getErrorType();
43+
44+
/**
45+
* Return the path to a response field which experienced the error,
46+
* if the error can be associated to a particular field in the result. This
47+
* allows a client to identify whether a {@code null} result is intentional
48+
* or caused by an error.
49+
* <p>This list contains path segments starting at the root of the response
50+
* and ending with the field associated with the error. Path segments that
51+
* represent fields are strings, and path segments that represent list
52+
* indices are 0-indexed integers. If the error happens in an aliased field,
53+
* the path uses the aliased name, since it represents a path in the
54+
* response, not in the request.
55+
*/
56+
@Nullable
57+
List<Object> getPath();
58+
59+
/**
60+
* Return a map with GraphQL Java specific error details such as the
61+
* {@link #getErrorType()}.
62+
*/
63+
@Nullable
64+
Map<String, Object> getExtensions();
65+
66+
}

spring-graphql/src/main/java/org/springframework/graphql/RequestOutput.java

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,13 @@
1818
import java.util.Collections;
1919
import java.util.List;
2020
import java.util.Map;
21+
import java.util.stream.Collectors;
2122

23+
import graphql.ErrorClassification;
2224
import graphql.ExecutionInput;
2325
import graphql.ExecutionResult;
2426
import graphql.GraphQLError;
27+
import graphql.language.SourceLocation;
2528

2629
import org.springframework.lang.Nullable;
2730
import org.springframework.util.Assert;
@@ -55,9 +58,7 @@ public RequestOutput(ExecutionInput input, ExecutionResult result) {
5558
* Constructor to re-wrap from transport specific subclass.
5659
*/
5760
protected RequestOutput(RequestOutput requestOutput) {
58-
Assert.notNull(requestOutput, "RequestOutput is required.");
59-
this.input = requestOutput.getExecutionInput();
60-
this.result = requestOutput.result;
61+
this(requestOutput.getExecutionInput(), requestOutput.result);
6162
}
6263

6364

@@ -84,8 +85,8 @@ public <T> T getData() {
8485
return this.result.getData();
8586
}
8687

87-
public List<GraphQLError> getErrors() {
88-
return this.result.getErrors();
88+
public List<GraphQlResponseError> getErrors() {
89+
return this.result.getErrors().stream().map(OutputError::new).collect(Collectors.toList());
8990
}
9091

9192
public Map<Object, Object> getExtensions() {
@@ -102,4 +103,41 @@ public String toString() {
102103
return this.result.toString();
103104
}
104105

106+
107+
private static class OutputError implements GraphQlResponseError {
108+
109+
private final GraphQLError delegate;
110+
111+
OutputError(GraphQLError delegate) {
112+
this.delegate = delegate;
113+
}
114+
115+
@Override
116+
public String getMessage() {
117+
return this.delegate.getMessage();
118+
}
119+
120+
@Override
121+
public List<SourceLocation> getLocations() {
122+
return this.delegate.getLocations();
123+
}
124+
125+
@Override
126+
public ErrorClassification getErrorType() {
127+
return this.delegate.getErrorType();
128+
}
129+
130+
@Override
131+
public List<Object> getPath() {
132+
return this.delegate.getPath();
133+
}
134+
135+
@Override
136+
public Map<String, Object> getExtensions() {
137+
return this.delegate.getExtensions();
138+
}
139+
140+
}
141+
142+
105143
}

0 commit comments

Comments
 (0)