Skip to content

Commit a699823

Browse files
committed
Allow accessing headers from invalid responses
1 parent 46824f3 commit a699823

File tree

3 files changed

+95
-1
lines changed

3 files changed

+95
-1
lines changed

client/api/src/main/java/io/smallrye/graphql/client/InvalidResponseException.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package io.smallrye.graphql.client;
22

3+
import java.util.List;
4+
import java.util.Map;
5+
36
/**
47
* Marks a response that had unexpected contents and the client was unable to properly process it.
58
* This can be either due to an error on the server side (returning non-conformant responses),
@@ -8,12 +11,30 @@
811
*/
912
public class InvalidResponseException extends RuntimeException {
1013

14+
private final Map<String, List<String>> transportMeta;
15+
1116
public InvalidResponseException(String message) {
1217
super(message);
18+
this.transportMeta = null;
1319
}
1420

1521
public InvalidResponseException(String message, Throwable cause) {
1622
super(message, cause);
23+
this.transportMeta = null;
24+
}
25+
26+
public InvalidResponseException(String message, Throwable cause, Map<String, List<String>> transportMeta) {
27+
super(message, cause);
28+
this.transportMeta = transportMeta;
29+
}
30+
31+
/**
32+
* Get transport-specific metadata that came from the server with the invalid response.
33+
* For HTTP, these are the response headers. It can be null if headers aren't applicable, for example
34+
* if this is coming from a message received over a WebSocket connection.
35+
*/
36+
public Map<String, List<String>> getTransportMeta() {
37+
return transportMeta;
1738
}
1839

1940
}

client/implementation/src/main/java/io/smallrye/graphql/client/impl/ResponseReader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public static ResponseImpl readFrom(String input, Map<String, List<String>> head
7979
if (jsonResponse == null) {
8080
throw new InvalidResponseException(
8181
"Unexpected response. Code=" + statusCode + ", message=\"" + statusMessage + "\", " +
82-
"body=\"" + input + "\"");
82+
"body=\"" + input + "\"", null, headers);
8383
}
8484
JsonObject data = null;
8585
if (jsonResponse.containsKey("data")) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package io.smallrye.graphql.tests.client.dynamic.error;
2+
3+
import io.smallrye.graphql.client.InvalidResponseException;
4+
import io.smallrye.graphql.client.vertx.dynamic.VertxDynamicGraphQLClient;
5+
import io.smallrye.graphql.client.vertx.dynamic.VertxDynamicGraphQLClientBuilder;
6+
import jakarta.servlet.ServletException;
7+
import jakarta.servlet.annotation.WebServlet;
8+
import jakarta.servlet.http.HttpServlet;
9+
import jakarta.servlet.http.HttpServletRequest;
10+
import jakarta.servlet.http.HttpServletResponse;
11+
import org.jboss.arquillian.container.test.api.Deployment;
12+
import org.jboss.arquillian.container.test.api.RunAsClient;
13+
import org.jboss.arquillian.junit.Arquillian;
14+
import org.jboss.arquillian.test.api.ArquillianResource;
15+
import org.jboss.shrinkwrap.api.ShrinkWrap;
16+
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
17+
import org.jboss.shrinkwrap.api.spec.WebArchive;
18+
import org.junit.Assert;
19+
import org.junit.Before;
20+
import org.junit.Test;
21+
import org.junit.runner.RunWith;
22+
23+
import java.io.IOException;
24+
import java.net.URL;
25+
import java.util.concurrent.ExecutionException;
26+
27+
/**
28+
* Verify that the client allows access to HTTP response headers when an invalid response is received.
29+
* In this test, a servlet is used to return a 418 I'm a teapot response with a custom header.
30+
* The client then makes a request and verifies that the InvalidResponseException contains the custom header.
31+
*/
32+
@RunWith(Arquillian.class)
33+
@RunAsClient
34+
public class TypesafeClientInvalidResponseTest {
35+
36+
@Deployment
37+
public static WebArchive deployment() {
38+
return ShrinkWrap.create(WebArchive.class, "init-payload-test.war")
39+
.addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml")
40+
.addClasses(ErrorServlet.class);
41+
}
42+
43+
@WebServlet(urlPatterns = {"/graphql"})
44+
public static class ErrorServlet extends HttpServlet {
45+
@Override
46+
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
47+
resp.setStatus(418); // I'm a teapot
48+
resp.setHeader("Teapot-Color", "Yellow");
49+
}
50+
}
51+
52+
@ArquillianResource
53+
URL testingURL;
54+
55+
private static VertxDynamicGraphQLClient client;
56+
57+
@Before
58+
public void prepare() {
59+
client = (VertxDynamicGraphQLClient) new VertxDynamicGraphQLClientBuilder()
60+
.url(testingURL.toString() + "graphql")
61+
.build();
62+
}
63+
64+
@Test
65+
public void receiveImATeapotResponse() throws ExecutionException, InterruptedException {
66+
try {
67+
client.executeSync("{}");
68+
} catch (InvalidResponseException ex) {
69+
Assert.assertEquals("Yellow", ex.getTransportMeta().get("Teapot-Color").get(0));
70+
}
71+
}
72+
73+
}

0 commit comments

Comments
 (0)