Skip to content

Commit 5e95fcf

Browse files
committed
Refine getError(s) methods on ResponseField
getError now returns either the error at the field or on a parent field, which provides a reliable answer for why a field failed even for a field whose path is below where the error occurred. getErrors likewise now also includes errors above. There is still no need for special logic to get only errors below since where there is a field value, errors are below anyway. See gh-10
1 parent f28d3dc commit 5e95fcf

File tree

5 files changed

+27
-9
lines changed

5 files changed

+27
-9
lines changed

spring-graphql/src/main/java/org/springframework/graphql/client/DefaultClientGraphQlResponse.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ public <T> T getValue() {
136136
@Override
137137
public GraphQLError getError() {
138138
for (GraphQLError error : this.errors) {
139-
if (this.parsedPath.size() == error.getPath().size()) {
139+
if (error.getPath().size() <= this.parsedPath.size()) {
140140
return error;
141141
}
142142
}

spring-graphql/src/main/java/org/springframework/graphql/client/ResponseField.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,15 +60,24 @@ public interface ResponseField {
6060
<T> T getValue();
6161

6262
/**
63-
* Return the first error whose path is equal to the field path.
64-
* <p>According to section 6.4.4 "Handling Field Errors" of the GraphQL
65-
* spec, only one error should be added to the errors list per field.
63+
* Return the error for this field, if any. The error may be for this field
64+
* when the field is {@code null}, or it may be for a parent field, when the
65+
* current field does not exist.
66+
* <p><strong>Note:</strong> The field error is identified by searching for
67+
* the first error with a matching path that is shorter or the same as the
68+
* field path. According to the GraphQL spec, section 6.4.4,
69+
* "Handling Field Errors", there should be only one field error per field.
70+
* @return return the error for this field, or {@code null} if there is no
71+
* error with the same path as the field path
6672
*/
6773
@Nullable
6874
GraphQLError getError();
6975

7076
/**
71-
* Return all field errors including those whose path is below the field path.
77+
* Return all field errors including errors above, at, and below this field.
78+
* <p>In practice, when the field has a value, all errors are for fields
79+
* below. When the field does not have a value, there is only one error, and
80+
* it is the same as {@link #getError()}.
7281
*/
7382
List<GraphQLError> getErrors();
7483

spring-graphql/src/main/java/org/springframework/graphql/support/MapGraphQlResponse.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,11 +185,11 @@ protected List<GraphQLError> getFieldErrors(List<Object> fieldPath) {
185185
List<GraphQLError> fieldErrors = Collections.emptyList();
186186
for (GraphQLError error : this.errors) {
187187
List<Object> errorPath = error.getPath();
188-
if (CollectionUtils.isEmpty(errorPath) || errorPath.size() < fieldPath.size()) {
188+
if (CollectionUtils.isEmpty(errorPath)) {
189189
continue;
190190
}
191191
boolean match = true;
192-
for (int i = 0; match && i < fieldPath.size(); i++) {
192+
for (int i = 0; match && i < fieldPath.size() && i < errorPath.size(); i++) {
193193
match = fieldPath.get(i).equals(errorPath.get(i));
194194
}
195195
if (!match) {

spring-graphql/src/test/java/org/springframework/graphql/client/GraphQlClientTests.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,15 +188,24 @@ void executePartialResponse() {
188188

189189
ResponseField field = response.field("me");
190190
assertThat(field.isValid()).isTrue();
191+
assertThat(field.getErrors()).hasSize(1);
192+
assertThat(field.getErrors().get(0).getPath()).containsExactly("me", "name");
191193
assertThat(field.toEntity(MovieCharacter.class))
192194
.as("Decoding with nested field error should not be precluded")
193195
.isNotNull();
194196

195197
ResponseField nameField = response.field("me.name");
196198
assertThat(nameField.isValid()).isFalse();
199+
assertThat(nameField.getError()).isNotNull();
200+
assertThat(nameField.getError().getPath()).containsExactly("me", "name");
197201
assertThatThrownBy(() -> nameField.toEntity(String.class))
198202
.as("Decoding field null with direct field error should be rejected")
199203
.isInstanceOf(FieldAccessException.class);
204+
205+
ResponseField nonExistingField = response.field("me.name.other");
206+
assertThat(nonExistingField.isValid()).isFalse();
207+
assertThat(nameField.getError()).isNotNull();
208+
assertThat(nameField.getError().getPath()).containsExactly("me", "name");
200209
}
201210

202211
private GraphQLError errorForPath(String errorPath) {

spring-graphql/src/test/java/org/springframework/graphql/support/MapGraphQlResponseTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,11 +142,11 @@ void fieldErrors() {
142142
MapGraphQlResponse response = MapGraphQlResponse.forErrorsOnly(errorList);
143143
List<GraphQLError> errors = response.getFieldErrors(path);
144144

145-
assertThat(errors).containsExactly(error2, error3);
145+
assertThat(errors).containsExactly(error1, error2, error3);
146146
}
147147

148148
private GraphQLError createError(@Nullable String errorPath, String message) {
149-
GraphqlErrorBuilder builder = GraphqlErrorBuilder.newError().message(message);
149+
GraphqlErrorBuilder<?> builder = GraphqlErrorBuilder.newError().message(message);
150150
if (errorPath != null) {
151151
builder = builder.path(ResultPath.parse(errorPath));
152152
}

0 commit comments

Comments
 (0)