Skip to content

Commit 4a00164

Browse files
committed
feat: implement support for general GraphQL Request and Response
1 parent 04af6e3 commit 4a00164

File tree

4 files changed

+138
-2
lines changed

4 files changed

+138
-2
lines changed

src/main/java/org/kohsuke/github/GitHub.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1299,6 +1299,18 @@ Requester createRequest() {
12991299
return requester;
13001300
}
13011301

1302+
/**
1303+
* Creates a request to GitHub GraphQL API.
1304+
*
1305+
* @param query
1306+
* the query for the GraphQL
1307+
* @return the requester
1308+
*/
1309+
@Nonnull
1310+
Requester createGraphQLRequest(String query) {
1311+
return createRequest().method("POST").with("query", query).withUrlPath("/graphql");
1312+
}
1313+
13021314
/**
13031315
* Intern.
13041316
*

src/main/java/org/kohsuke/github/GitHubResponse.java

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
package org.kohsuke.github;
22

33
import com.fasterxml.jackson.core.JsonParseException;
4-
import com.fasterxml.jackson.databind.InjectableValues;
5-
import com.fasterxml.jackson.databind.JsonMappingException;
4+
import com.fasterxml.jackson.databind.*;
65
import org.apache.commons.io.IOUtils;
76
import org.kohsuke.github.connector.GitHubConnectorResponse;
7+
import org.kohsuke.github.graphql.response.GHGraphQLResponse;
88

99
import java.io.IOException;
1010
import java.io.InputStream;
@@ -136,6 +136,45 @@ static <T> T parseBody(GitHubConnectorResponse connectorResponse, T instance) th
136136
}
137137
}
138138

139+
/**
140+
* Parses a {@link GitHubConnectorResponse} body into a new instance of {@code GHGraphQLResponse<T>}.
141+
*
142+
* @param <T>
143+
* the type
144+
* @param connectorResponse
145+
* the response info to parse.
146+
* @param type
147+
* the type to be constructed in GraphQLResponse.
148+
* @return GHGraphQLResponse
149+
*
150+
* @throws IOException
151+
* if there is an I/O Exception.
152+
*/
153+
@CheckForNull
154+
static <T> GHGraphQLResponse<T> parseGraphQLBody(GitHubConnectorResponse connectorResponse, Class<T> type)
155+
throws IOException {
156+
if (connectorResponse.statusCode() == HTTP_NO_CONTENT) {
157+
if (type != null && type.isArray()) {
158+
T emptyArray = type.cast(Array.newInstance(type.getComponentType(), 0));
159+
return new GHGraphQLResponse<>(emptyArray, null);
160+
} else {
161+
return new GHGraphQLResponse<>(null, null);
162+
}
163+
}
164+
165+
String data = getBodyAsString(connectorResponse);
166+
try {
167+
ObjectReader objectReader = GitHubClient.getMappingObjectReader(connectorResponse);
168+
JavaType targetType = objectReader.getTypeFactory().constructParametricType(GHGraphQLResponse.class, type);
169+
ObjectReader targetReader = objectReader.forType(targetType);
170+
return targetReader.readValue(data);
171+
} catch (JsonMappingException | JsonParseException e) {
172+
String message = "Failed to deserialize: " + data;
173+
LOGGER.log(Level.FINE, message);
174+
throw e;
175+
}
176+
}
177+
139178
/**
140179
* Gets the body of the response as a {@link String}.
141180
*

src/main/java/org/kohsuke/github/Requester.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.apache.commons.io.IOUtils;
2828
import org.kohsuke.github.connector.GitHubConnectorResponse;
2929
import org.kohsuke.github.function.InputStreamFunction;
30+
import org.kohsuke.github.graphql.response.GHGraphQLResponse;
3031

3132
import java.io.ByteArrayInputStream;
3233
import java.io.IOException;
@@ -103,6 +104,22 @@ public <T> T fetchInto(@Nonnull T existingInstance) throws IOException {
103104
.body();
104105
}
105106

107+
/**
108+
* Sends a request and parses the response into the given type via databinding in graphQL response.
109+
*
110+
* @param <T>
111+
* the type parameter
112+
* @param type
113+
* the type
114+
* @return an instance of {@code GHGraphQLResponse<T>}
115+
* @throws IOException
116+
* if the server returns 4xx/5xx responses.
117+
*/
118+
public <T> GHGraphQLResponse<T> fetchGraphQLResponse(@Nonnull Class<T> type) throws IOException {
119+
return client.sendRequest(this, connectorResponse -> GitHubResponse.parseGraphQLBody(connectorResponse, type))
120+
.body();
121+
}
122+
106123
/**
107124
* Makes a request and just obtains the HTTP status code. Method does not throw exceptions for many status codes
108125
* that would otherwise throw.
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package org.kohsuke.github.graphql.response;
2+
3+
import com.fasterxml.jackson.annotation.JsonCreator;
4+
import com.fasterxml.jackson.annotation.JsonProperty;
5+
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
6+
7+
import java.util.List;
8+
import java.util.stream.Collectors;
9+
10+
/**
11+
* A response of GraphQL.
12+
* <p>
13+
* This class is used to parse the response of GraphQL.
14+
* </p>
15+
*
16+
* @param <T>
17+
* the type of data
18+
*/
19+
public class GHGraphQLResponse<T> {
20+
21+
private final T data;
22+
23+
private final List<GHGraphQLError> errors;
24+
25+
@JsonCreator
26+
@SuppressFBWarnings(value = { "EI_EXPOSE_REP2" }, justification = "Spotbugs also doesn't like this")
27+
public GHGraphQLResponse(@JsonProperty("data") T data, @JsonProperty("errors") List<GHGraphQLError> errors) {
28+
this.data = data;
29+
this.errors = errors;
30+
}
31+
32+
public Boolean isSuccessful() {
33+
return errors == null || errors.isEmpty();
34+
}
35+
36+
public T getData() {
37+
if (!isSuccessful()) {
38+
throw new RuntimeException("This response is Errors occurred response");
39+
}
40+
41+
return data;
42+
}
43+
44+
public List<String> getErrorMessages() {
45+
if (isSuccessful()) {
46+
throw new RuntimeException("No errors occurred");
47+
}
48+
49+
return errors.stream().map(GHGraphQLError::getErrorMessage).collect(Collectors.toList());
50+
}
51+
52+
/**
53+
* A error of GraphQL response. Minimum implementation for GraphQL error.
54+
*/
55+
private static class GHGraphQLError {
56+
57+
private final String errorMessage;
58+
59+
@JsonCreator
60+
public GHGraphQLError(@JsonProperty("message") String errorMessage) {
61+
this.errorMessage = errorMessage;
62+
}
63+
64+
public String getErrorMessage() {
65+
return errorMessage;
66+
}
67+
}
68+
}

0 commit comments

Comments
 (0)