Skip to content
This repository was archived by the owner on Dec 19, 2023. It is now read-only.

Commit 740491f

Browse files
fix(#524): return valid error even if request body is invalid
A valid GraphQL error response is returned with a descriptive error message instead of HTTP 500 with internal details. Details of the parse error is logged server-side.
1 parent ffcb1c6 commit 740491f

File tree

3 files changed

+71
-3
lines changed

3 files changed

+71
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package graphql.kickstart.spring.webflux.boot;
2+
3+
import java.io.IOException;
4+
import java.nio.charset.StandardCharsets;
5+
import org.assertj.core.util.Files;
6+
import org.junit.jupiter.api.DisplayName;
7+
import org.junit.jupiter.params.ParameterizedTest;
8+
import org.junit.jupiter.params.provider.ValueSource;
9+
import org.springframework.beans.factory.annotation.Autowired;
10+
import org.springframework.boot.test.context.SpringBootTest;
11+
import org.springframework.core.io.ClassPathResource;
12+
import org.springframework.http.HttpStatus;
13+
import org.springframework.http.MediaType;
14+
import org.springframework.test.web.reactive.server.WebTestClient;
15+
16+
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
17+
public class InvalidJsonRequestTest {
18+
19+
@Autowired private WebTestClient webTestClient;
20+
21+
@ParameterizedTest
22+
@ValueSource(strings = {"\"false\":true", "not-a-json"})
23+
@DisplayName("Should return valid response to a request with invalid JSON or non-JSON body.")
24+
void testHandlingInvalidJsonRequest(String badRequestBody) throws IOException {
25+
// GIVEN
26+
final String expectedJson =
27+
Files.contentOf(
28+
new ClassPathResource("response-to-invalid-request.json").getFile(),
29+
StandardCharsets.UTF_8);
30+
// WHEN - THEN
31+
webTestClient
32+
.post()
33+
.uri("/graphql")
34+
.contentType(MediaType.APPLICATION_JSON)
35+
.bodyValue(badRequestBody)
36+
.exchange()
37+
.expectStatus()
38+
.isEqualTo(HttpStatus.OK)
39+
.expectBody()
40+
.json(expectedJson);
41+
}
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"errors": [
3+
{
4+
"message": "Bad request - invalid request body.",
5+
"locations": []
6+
}
7+
],
8+
"data": null
9+
}

graphql-kickstart-spring-support/src/main/java/graphql/kickstart/spring/AbstractGraphQLController.java

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
package graphql.kickstart.spring;
22

3+
import graphql.ExecutionResultImpl;
34
import graphql.kickstart.execution.GraphQLObjectMapper;
45
import graphql.kickstart.execution.GraphQLRequest;
6+
import graphql.kickstart.execution.error.GenericGraphQLError;
57
import java.io.IOException;
68
import java.util.Collections;
79
import java.util.Map;
810
import java.util.Optional;
911
import lombok.RequiredArgsConstructor;
12+
import lombok.extern.slf4j.Slf4j;
1013
import org.springframework.http.HttpHeaders;
1114
import org.springframework.http.HttpStatus;
1215
import org.springframework.http.MediaType;
@@ -20,8 +23,11 @@
2023
import org.springframework.web.server.ServerWebExchange;
2124

2225
@RequiredArgsConstructor
26+
@Slf4j
2327
public abstract class AbstractGraphQLController {
2428

29+
private static final String INVALID_REQUEST_BODY_MESSAGE = "Bad request - invalid request body.";
30+
2531
private final GraphQLObjectMapper objectMapper;
2632

2733
@PostMapping(
@@ -34,13 +40,17 @@ public Object graphqlPOST(
3440
@Nullable @RequestParam(value = "operationName", required = false) String operationName,
3541
@Nullable @RequestParam(value = "variables", required = false) String variablesJson,
3642
@Nullable @RequestBody(required = false) String body,
37-
ServerWebExchange serverWebExchange)
38-
throws IOException {
43+
ServerWebExchange serverWebExchange) {
3944

4045
body = Optional.ofNullable(body).orElse("");
4146

4247
if (MediaType.APPLICATION_JSON.isCompatibleWith(contentType)) {
43-
GraphQLRequest request = objectMapper.readGraphQLRequest(body);
48+
GraphQLRequest request;
49+
try {
50+
request = objectMapper.readGraphQLRequest(body);
51+
} catch (IOException e) {
52+
return handleBodyParsingException(e, serverWebExchange);
53+
}
4454
if (request.getQuery() == null) {
4555
request.setQuery("");
4656
}
@@ -95,4 +105,11 @@ protected abstract Object executeRequest(
95105
String operationName,
96106
Map<String, Object> variables,
97107
ServerWebExchange serverWebExchange);
108+
109+
protected Object handleBodyParsingException(
110+
Exception exception, ServerWebExchange serverWebExchange) {
111+
log.error("{} {}", INVALID_REQUEST_BODY_MESSAGE, exception.getMessage());
112+
return objectMapper.createResultFromExecutionResult(
113+
new ExecutionResultImpl(new GenericGraphQLError(INVALID_REQUEST_BODY_MESSAGE)));
114+
}
98115
}

0 commit comments

Comments
 (0)