Support for response headers through WebOutput
See gh-6
This commit is contained in:
@@ -51,7 +51,13 @@ public class WebFluxGraphQLHandler implements HandlerFunction<ServerResponse> {
|
||||
WebInput webInput = new WebInput(request.uri(), request.headers().asHttpHeaders(), body);
|
||||
return this.executionChain.execute(webInput);
|
||||
})
|
||||
.flatMap(output -> ServerResponse.ok().bodyValue(output.toSpecification()));
|
||||
.flatMap(output -> {
|
||||
ServerResponse.BodyBuilder builder = ServerResponse.ok();
|
||||
if (output.getHeaders() != null) {
|
||||
builder.headers(headers -> headers.putAll(output.getHeaders()));
|
||||
}
|
||||
return builder.bodyValue(output.toSpecification());
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ class WebInterceptorExecutionChain {
|
||||
}
|
||||
|
||||
private Mono<WebOutput> createOutputChain(Mono<ExecutionResult> resultMono) {
|
||||
Mono<WebOutput> outputMono = resultMono.map(WebOutput::new);
|
||||
Mono<WebOutput> outputMono = resultMono.map((ExecutionResult executionResult) -> new WebOutput(executionResult, null));
|
||||
for (int i = this.interceptors.size() - 1 ; i >= 0; i--) {
|
||||
WebInterceptor interceptor = this.interceptors.get(i);
|
||||
outputMono = outputMono.flatMap(interceptor::postHandle);
|
||||
|
||||
@@ -21,7 +21,6 @@ import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import graphql.ExecutionResult;
|
||||
import graphql.GraphQL;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@@ -60,8 +59,15 @@ public class WebMvcGraphQLHandler implements HandlerFunction<ServerResponse> {
|
||||
*/
|
||||
public ServerResponse handle(ServerRequest request) throws ServletException {
|
||||
WebInput webInput = new WebInput(request.uri(), request.headers().asHttpHeaders(), readBody(request));
|
||||
Mono<WebOutput> outputMono = this.executionChain.execute(webInput);
|
||||
return ServerResponse.ok().body(outputMono.map(ExecutionResult::toSpecification));
|
||||
Mono<ServerResponse> responseMono = this.executionChain.execute(webInput)
|
||||
.map(output -> {
|
||||
ServerResponse.BodyBuilder builder = ServerResponse.ok();
|
||||
if (output.getHeaders() != null) {
|
||||
builder.headers(headers -> headers.putAll(output.getHeaders()));
|
||||
}
|
||||
return builder.body(output.toSpecification());
|
||||
});
|
||||
return ServerResponse.async(responseMono);
|
||||
}
|
||||
|
||||
private static Map<String, Object> readBody(ServerRequest request) throws ServletException {
|
||||
|
||||
@@ -24,6 +24,7 @@ import graphql.ExecutionResult;
|
||||
import graphql.ExecutionResultImpl;
|
||||
import graphql.GraphQLError;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
|
||||
@@ -35,12 +36,16 @@ public class WebOutput implements ExecutionResult {
|
||||
|
||||
private final ExecutionResult executionResult;
|
||||
|
||||
@Nullable
|
||||
private final HttpHeaders headers;
|
||||
|
||||
|
||||
/**
|
||||
* Create an instance that wraps the given {@link ExecutionResult}.
|
||||
*/
|
||||
public WebOutput(ExecutionResult executionResult) {
|
||||
public WebOutput(ExecutionResult executionResult, @Nullable HttpHeaders headers) {
|
||||
this.executionResult = executionResult;
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
|
||||
@@ -69,6 +74,14 @@ public class WebOutput implements ExecutionResult {
|
||||
return this.executionResult.toSpecification();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return headers to be added to the HTTP response.
|
||||
*/
|
||||
@Nullable
|
||||
public HttpHeaders getHeaders() {
|
||||
return this.headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform this {@code WebOutput} instance through a {@link Builder} and
|
||||
* return a new instance with the modified values.
|
||||
@@ -90,12 +103,18 @@ public class WebOutput implements ExecutionResult {
|
||||
@Nullable
|
||||
private Map<Object, Object> extensions;
|
||||
|
||||
@Nullable
|
||||
private HttpHeaders headers;
|
||||
|
||||
|
||||
public Builder(WebOutput output) {
|
||||
this.data = output.getData();
|
||||
this.errors = output.getErrors();
|
||||
this.extensions = output.getExtensions();
|
||||
this.headers = output.getHeaders();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the execution {@link ExecutionResult#getData() data}.
|
||||
*/
|
||||
@@ -120,8 +139,26 @@ public class WebOutput implements ExecutionResult {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder header(String name, String... values) {
|
||||
initHeaders();
|
||||
for (String value : values) {
|
||||
this.headers.add(name, value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder headers(Consumer<HttpHeaders> consumer) {
|
||||
initHeaders();
|
||||
consumer.accept(this.headers);
|
||||
return this;
|
||||
}
|
||||
|
||||
private void initHeaders() {
|
||||
this.headers = (this.headers != null ? this.headers : new HttpHeaders());
|
||||
}
|
||||
|
||||
public WebOutput build() {
|
||||
return new WebOutput(new ExecutionResultImpl(this.data, this.errors, this.extensions));
|
||||
return new WebOutput(new ExecutionResultImpl(this.data, this.errors, this.extensions), this.headers);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -69,8 +69,10 @@ public class WebInterceptorExecutionChainTests {
|
||||
|
||||
assertThat(sb.toString()).isEqualTo(":pre1:pre2:pre3:post3:post2:post1");
|
||||
assertThat(webOutput.isDataPresent()).isTrue();
|
||||
assertThat(webOutput.getHeaders().get("MyHeader")).containsExactly("MyValue3", "MyValue2", "MyValue1");
|
||||
}
|
||||
|
||||
|
||||
private static GraphQL createGraphQL() throws Exception {
|
||||
RuntimeWiring runtimeWiring = RuntimeWiring.newRuntimeWiring()
|
||||
.type(newTypeWiring("Query").dataFetcher("bookById", GraphQLDataFetchers.getBookByIdDataFetcher()))
|
||||
@@ -105,7 +107,10 @@ public class WebInterceptorExecutionChainTests {
|
||||
@Override
|
||||
public Mono<WebOutput> postHandle(WebOutput webOutput) {
|
||||
this.output.append(":post").append(this.index);
|
||||
return Mono.delay(Duration.ofMillis(50)).map(aLong -> webOutput);
|
||||
return Mono.delay(Duration.ofMillis(50))
|
||||
.map(aLong -> webOutput.transform(builder -> {
|
||||
builder.header("myHeader", "MyValue" + this.index);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user