Skip to content

Allow batch handler to set http status #156

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -365,12 +365,7 @@ private void query(GraphQLQueryInvoker queryInvoker, GraphQLObjectMapper graphQL
}

private void queryBatched(GraphQLQueryInvoker queryInvoker, GraphQLObjectMapper graphQLObjectMapper, GraphQLBatchedInvocationInput invocationInput, HttpServletResponse resp) throws Exception {
resp.setContentType(APPLICATION_JSON_UTF8);
resp.setStatus(STATUS_OK);

Writer respWriter = resp.getWriter();

queryInvoker.query(invocationInput, respWriter, graphQLObjectMapper);
queryInvoker.query(invocationInput, resp, graphQLObjectMapper);
}

private <R> List<R> runListeners(Function<? super GraphQLServletListener, R> action) {
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/graphql/servlet/BatchExecutionHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import graphql.ExecutionInput;
import graphql.ExecutionResult;

import javax.servlet.http.HttpServletResponse;
import java.io.Writer;
import java.util.function.BiFunction;

Expand All @@ -16,9 +17,9 @@ public interface BatchExecutionHandler {
* @param batchedInvocationInput the batch query input
* @param queryFunction Function to produce query results.
* @param graphQLObjectMapper object mapper used to serialize results
* @param writer request writer to ouput results.
* @param response http response object
*/
void handleBatch(GraphQLBatchedInvocationInput batchedInvocationInput, Writer writer, GraphQLObjectMapper graphQLObjectMapper,
void handleBatch(GraphQLBatchedInvocationInput batchedInvocationInput, HttpServletResponse response, GraphQLObjectMapper graphQLObjectMapper,
BiFunction<GraphQLInvocationInput, ExecutionInput, ExecutionResult> queryFunction);
}

Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import graphql.ExecutionInput;
import graphql.ExecutionResult;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.Writer;
import java.util.Iterator;
Expand All @@ -11,10 +12,14 @@
public class DefaultBatchExecutionHandler implements BatchExecutionHandler {

@Override
public void handleBatch(GraphQLBatchedInvocationInput batchedInvocationInput, Writer writer, GraphQLObjectMapper graphQLObjectMapper,
public void handleBatch(GraphQLBatchedInvocationInput batchedInvocationInput, HttpServletResponse response, GraphQLObjectMapper graphQLObjectMapper,
BiFunction<GraphQLInvocationInput, ExecutionInput, ExecutionResult> queryFunction) {
Iterator<ExecutionInput> executionInputIterator = batchedInvocationInput.getExecutionInputs().iterator();
response.setContentType(AbstractGraphQLHttpServlet.APPLICATION_JSON_UTF8);
response.setStatus(AbstractGraphQLHttpServlet.STATUS_OK);
try {
Writer writer = response.getWriter();
Iterator<ExecutionInput> executionInputIterator = batchedInvocationInput.getExecutionInputs().iterator();

writer.write("[");
while (executionInputIterator.hasNext()) {
ExecutionResult result = queryFunction.apply(batchedInvocationInput, executionInputIterator.next());
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/graphql/servlet/GraphQLQueryInvoker.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import graphql.schema.GraphQLSchema;

import javax.security.auth.Subject;
import javax.servlet.http.HttpServletResponse;
import java.io.Writer;
import java.security.AccessController;
import java.security.PrivilegedAction;
Expand Down Expand Up @@ -43,8 +44,8 @@ public ExecutionResult query(GraphQLSingleInvocationInput singleInvocationInput)
return query(singleInvocationInput, singleInvocationInput.getExecutionInput());
}

public void query(GraphQLBatchedInvocationInput batchedInvocationInput, Writer writer, GraphQLObjectMapper graphQLObjectMapper) {
batchExecutionHandler.handleBatch(batchedInvocationInput, writer, graphQLObjectMapper, this::query);
public void query(GraphQLBatchedInvocationInput batchedInvocationInput, HttpServletResponse response, GraphQLObjectMapper graphQLObjectMapper) {
batchExecutionHandler.handleBatch(batchedInvocationInput, response, graphQLObjectMapper, this::query);
}

private GraphQL newGraphQL(GraphQLSchema schema, Object context) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ class AbstractGraphQLHttpServletSpec extends Specification {
getBatchedResponseContent()[1].data.echo == "test"
}

def "Execution Result Handler allows limiting number of queries"() {
def "Batch Execution Handler allows limiting batches and sending error messages."() {
setup:
servlet = TestUtils.createBatchCustomizedServlet({ env -> env.arguments.arg }, { env -> env.arguments.arg }, { env ->
AtomicReference<SingleSubscriberPublisher<String>> publisherRef = new AtomicReference<>()
Expand All @@ -304,9 +304,8 @@ class AbstractGraphQLHttpServletSpec extends Specification {
servlet.doGet(request, response)

then:
response.getStatus() == STATUS_OK
response.getContentType() == CONTENT_TYPE_JSON_UTF8
getBatchedResponseContent().size() == 2
response.getStatus() == STATUS_BAD_REQUEST
response.getErrorMessage() == TestBatchExecutionHandler.BATCH_ERROR_MESSAGE
}

def "Default Execution Result Handler does not limit number of queries"() {
Expand Down
27 changes: 22 additions & 5 deletions src/test/groovy/graphql/servlet/TestBatchExecutionHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import graphql.ExecutionInput;
import graphql.ExecutionResult;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.Writer;
import java.util.Iterator;
Expand All @@ -12,18 +13,34 @@

public class TestBatchExecutionHandler implements BatchExecutionHandler {

public static String BATCH_ERROR_MESSAGE = "Batch limit exceeded";

@Override
public void handleBatch(GraphQLBatchedInvocationInput batchedInvocationInput, Writer writer, GraphQLObjectMapper graphQLObjectMapper,
public void handleBatch(GraphQLBatchedInvocationInput batchedInvocationInput, HttpServletResponse response, GraphQLObjectMapper graphQLObjectMapper,
BiFunction<GraphQLInvocationInput, ExecutionInput, ExecutionResult> queryFunction) {
List<ExecutionResult> results = batchedInvocationInput.getExecutionInputs().parallelStream()
.limit(2)
List<ExecutionInput> inputs = batchedInvocationInput.getExecutionInputs();
if (inputs.size() > 2) {
handleBadInput(response);
}
List<ExecutionResult> results = inputs.parallelStream()
.map(input -> queryFunction.apply(batchedInvocationInput, input))
.collect(Collectors.toList());
writeResults(results, writer, graphQLObjectMapper);
writeResults(results, response, graphQLObjectMapper);
}

private void handleBadInput(HttpServletResponse response) {
try {
response.sendError(HttpServletResponse.SC_BAD_REQUEST, BATCH_ERROR_MESSAGE);
} catch (IOException e) {
throw new RuntimeException(e);
}
}

private void writeResults(List<ExecutionResult> results, Writer writer, GraphQLObjectMapper mapper) {
private void writeResults(List<ExecutionResult> results, HttpServletResponse response, GraphQLObjectMapper mapper) {
response.setContentType(AbstractGraphQLHttpServlet.APPLICATION_JSON_UTF8);
response.setStatus(AbstractGraphQLHttpServlet.STATUS_OK);
try {
Writer writer = response.getWriter();
writer.write("[");
Iterator<ExecutionResult> iter = results.iterator();
while (iter.hasNext()) {
Expand Down