Simplify access to response headers in WebOutput
The response headers can now be changed directly without the need to go through the builder. See gh-229
This commit is contained in:
@@ -29,6 +29,7 @@ import graphql.GraphQLError;
|
||||
import org.springframework.graphql.RequestOutput;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Decorate an {@link ExecutionResult}, provide a way to {@link #transform(Consumer)
|
||||
@@ -40,37 +41,35 @@ import org.springframework.lang.Nullable;
|
||||
*/
|
||||
public class WebOutput extends RequestOutput {
|
||||
|
||||
@Nullable
|
||||
private final HttpHeaders responseHeaders;
|
||||
|
||||
|
||||
/**
|
||||
* Create an instance that wraps the given {@link ExecutionResult}.
|
||||
* Create an instance from the given {@link RequestOutput}.
|
||||
* @param requestOutput the output from an executed request
|
||||
*/
|
||||
public WebOutput(RequestOutput requestOutput) {
|
||||
this(requestOutput.getExecutionInput(), requestOutput, null);
|
||||
this(requestOutput.getExecutionInput(), requestOutput, new HttpHeaders());
|
||||
}
|
||||
|
||||
private WebOutput(
|
||||
ExecutionInput executionInput, ExecutionResult executionResult,
|
||||
@Nullable HttpHeaders responseHeaders) {
|
||||
private WebOutput(ExecutionInput executionInput, ExecutionResult executionResult,
|
||||
HttpHeaders responseHeaders) {
|
||||
|
||||
super(executionInput, executionResult);
|
||||
Assert.notNull(responseHeaders, "HttpHeaders is required");
|
||||
this.responseHeaders = responseHeaders;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a read-only view of any custom headers to be added to the HTTP response, or
|
||||
* {@code null} until {@link #transform(Consumer)} is used to add such headers.
|
||||
* @return the read-only HTTP response headers
|
||||
* @see #transform(Consumer)
|
||||
* @see Builder#responseHeader(String, String...)
|
||||
* Return the headers to be added to the HTTP response.
|
||||
* <p>By default, this is empty.
|
||||
* <p><strong>Note:</strong> This is for use with GraphQL over HTTP requests
|
||||
* but not for GraphQL over WebSocket where the initial handshake HTTP
|
||||
* request completes before queries begin.
|
||||
*/
|
||||
@Nullable
|
||||
public HttpHeaders getResponseHeaders() {
|
||||
return (this.responseHeaders != null) ? HttpHeaders.readOnlyHttpHeaders(this.responseHeaders) : null;
|
||||
return this.responseHeaders;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,7 +90,7 @@ public class WebOutput extends RequestOutput {
|
||||
*/
|
||||
public static final class Builder {
|
||||
|
||||
private final ExecutionInput executionInput;
|
||||
private final WebOutput webOutput;
|
||||
|
||||
@Nullable
|
||||
private Object data;
|
||||
@@ -101,15 +100,11 @@ public class WebOutput extends RequestOutput {
|
||||
@Nullable
|
||||
private Map<Object, Object> extensions;
|
||||
|
||||
@Nullable
|
||||
private HttpHeaders headers;
|
||||
|
||||
private Builder(WebOutput output) {
|
||||
this.executionInput = output.getExecutionInput();
|
||||
this.webOutput = output;
|
||||
this.data = output.getData();
|
||||
this.errors = output.getErrors();
|
||||
this.extensions = output.getExtensions();
|
||||
this.headers = output.responseHeaders;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -144,48 +139,9 @@ public class WebOutput extends RequestOutput {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a custom header to be set on the HTTP response.
|
||||
*
|
||||
* <p>
|
||||
* <strong>Note:</strong> This can be used for GraphQL over HTTP requests but has
|
||||
* no impact for queries over a WebSocket session where the initial handshake
|
||||
* request completes before queries begin.
|
||||
* @param name the HTTP header name
|
||||
* @param values the HTTP header values
|
||||
* @return the current builder
|
||||
*/
|
||||
public Builder responseHeader(String name, String... values) {
|
||||
initHeaders();
|
||||
for (String value : values) {
|
||||
this.headers.add(name, value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Consume and update the headers to be set on the HTTP response.
|
||||
*
|
||||
* <p>
|
||||
* <strong>Note:</strong> This can be used for GraphQL over HTTP requests but has
|
||||
* no impact for queries over a WebSocket session where the initial handshake
|
||||
* request completes before queries begin.
|
||||
* @param consumer callback that updates the HTTP headers
|
||||
* @return the current builder
|
||||
*/
|
||||
public Builder responseHeaders(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() {
|
||||
ExecutionResult result = new ExecutionResultImpl(this.data, this.errors, this.extensions);
|
||||
return new WebOutput(this.executionInput, result, this.headers);
|
||||
return new WebOutput(this.webOutput.getExecutionInput(), result, this.webOutput.getResponseHeaders());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,9 +25,10 @@ public class ConsumeOneAndNeverCompleteInterceptor implements WebInterceptor {
|
||||
@Override
|
||||
public Mono<WebOutput> intercept(WebInput webInput, WebInterceptorChain chain) {
|
||||
return chain.next(webInput).map((output) -> output.transform(builder -> {
|
||||
if (output.getData() instanceof Publisher) {
|
||||
Flux<?> flux = Flux.from((Publisher<?>) output.getData()).take(1).concatWith(Flux.never());
|
||||
builder.data(flux);
|
||||
Object originalData = output.getData();
|
||||
if (originalData instanceof Publisher) {
|
||||
Flux<?> updatedData = Flux.from((Publisher<?>) originalData).take(1).concatWith(Flux.never());
|
||||
builder.data(updatedData);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -60,11 +60,12 @@ public class WebInterceptorTests {
|
||||
|
||||
@Test
|
||||
void responseHeader() {
|
||||
Function<WebOutput, WebOutput> headerFunction = (output) ->
|
||||
output.transform((builder) -> builder.responseHeader("testHeader", "testValue"));
|
||||
|
||||
WebGraphQlHandler handler = WebGraphQlHandler.builder(this::emptyExecutionResult)
|
||||
.interceptor((input, next) -> next.next(input).map(headerFunction))
|
||||
.interceptor((input, next) -> next.next(input)
|
||||
.doOnNext(output -> {
|
||||
HttpHeaders httpHeaders = output.getResponseHeaders();
|
||||
httpHeaders.add("testHeader", "testValue");
|
||||
}))
|
||||
.build();
|
||||
|
||||
HttpHeaders headers = handler.handleRequest(webInput).block().getResponseHeaders();
|
||||
|
||||
Reference in New Issue
Block a user