WebInterceptor contract revision
WebInterceptor now uses delegation, forming a chain of interceptors followed by a GraphQLService at the end to invoke graphql.GraphQL. Closes gh-49
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2002-2021 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.graphql.boot;
|
||||
|
||||
import graphql.GraphQL;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.graphql.GraphQLService;
|
||||
import org.springframework.graphql.support.ExecutionGraphQLService;
|
||||
import org.springframework.graphql.support.GraphQLSource;
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(GraphQL.class)
|
||||
@ConditionalOnMissingBean(GraphQLService.class)
|
||||
@AutoConfigureAfter(GraphQLAutoConfiguration.class)
|
||||
public class GraphQLServiceAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public GraphQLService graphQLService(GraphQLSource graphQLSource) {
|
||||
return new ExecutionGraphQLService(graphQLSource);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -34,9 +34,9 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.graphql.GraphQLService;
|
||||
import org.springframework.graphql.support.GraphQLSource;
|
||||
import org.springframework.graphql.web.DefaultWebGraphQLService;
|
||||
import org.springframework.graphql.web.WebGraphQLService;
|
||||
import org.springframework.graphql.web.WebGraphQLHandler;
|
||||
import org.springframework.graphql.web.WebInterceptor;
|
||||
import org.springframework.graphql.web.webflux.GraphQLHttpHandler;
|
||||
import org.springframework.graphql.web.webflux.GraphQLWebSocketHandler;
|
||||
@@ -64,16 +64,14 @@ public class WebFluxGraphQLAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public WebGraphQLService webGraphQLService(GraphQLSource graphQLSource, ObjectProvider<WebInterceptor> interceptors) {
|
||||
DefaultWebGraphQLService handler = new DefaultWebGraphQLService(graphQLSource);
|
||||
handler.setInterceptors(interceptors.orderedStream().collect(Collectors.toList()));
|
||||
return handler;
|
||||
public WebGraphQLHandler webGraphQLHandler(ObjectProvider<WebInterceptor> interceptors, GraphQLService service) {
|
||||
return WebInterceptor.createHandler(interceptors.orderedStream().collect(Collectors.toList()), service);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public GraphQLHttpHandler graphQLHandler(WebGraphQLService service) {
|
||||
return new GraphQLHttpHandler(service);
|
||||
public GraphQLHttpHandler graphQLHttpHandler(WebGraphQLHandler webGraphQLHandler) {
|
||||
return new GraphQLHttpHandler(webGraphQLHandler);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -99,22 +97,22 @@ public class WebFluxGraphQLAutoConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public GraphQLWebSocketHandler graphQLWebSocketHandler(
|
||||
WebGraphQLService service, GraphQLProperties properties, ServerCodecConfigurer configurer) {
|
||||
WebGraphQLHandler webGraphQLHandler, GraphQLProperties properties, ServerCodecConfigurer configurer) {
|
||||
|
||||
return new GraphQLWebSocketHandler(
|
||||
service, configurer, properties.getWebsocket().getConnectionInitTimeout());
|
||||
webGraphQLHandler, configurer, properties.getWebsocket().getConnectionInitTimeout());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HandlerMapping graphQLWebSocketEndpoint(
|
||||
GraphQLWebSocketHandler handler, GraphQLProperties properties) {
|
||||
GraphQLWebSocketHandler graphQLWebSocketHandler, GraphQLProperties properties) {
|
||||
|
||||
String path = properties.getWebsocket().getPath();
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("GraphQL endpoint WebSocket " + path);
|
||||
}
|
||||
WebSocketHandlerMapping handlerMapping = new WebSocketHandlerMapping();
|
||||
handlerMapping.setUrlMap(Collections.singletonMap(path, handler));
|
||||
handlerMapping.setUrlMap(Collections.singletonMap(path, graphQLWebSocketHandler));
|
||||
handlerMapping.setOrder(-2); // Ahead of HTTP endpoint ("routerFunctionMapping" bean)
|
||||
return handlerMapping;
|
||||
}
|
||||
|
||||
@@ -38,9 +38,9 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.graphql.GraphQLService;
|
||||
import org.springframework.graphql.support.GraphQLSource;
|
||||
import org.springframework.graphql.web.DefaultWebGraphQLService;
|
||||
import org.springframework.graphql.web.WebGraphQLService;
|
||||
import org.springframework.graphql.web.WebGraphQLHandler;
|
||||
import org.springframework.graphql.web.WebInterceptor;
|
||||
import org.springframework.graphql.web.webmvc.GraphQLHttpHandler;
|
||||
import org.springframework.graphql.web.webmvc.GraphQLWebSocketHandler;
|
||||
@@ -71,16 +71,14 @@ public class WebMvcGraphQLAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public WebGraphQLService webGraphQLService(GraphQLSource graphQLSource, ObjectProvider<WebInterceptor> interceptors) {
|
||||
DefaultWebGraphQLService handler = new DefaultWebGraphQLService(graphQLSource);
|
||||
handler.setInterceptors(interceptors.orderedStream().collect(Collectors.toList()));
|
||||
return handler;
|
||||
public WebGraphQLHandler webGraphQLHandler(ObjectProvider<WebInterceptor> interceptors, GraphQLService service) {
|
||||
return WebInterceptor.createHandler(interceptors.orderedStream().collect(Collectors.toList()), service);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public GraphQLHttpHandler graphQLHandler(WebGraphQLService service) {
|
||||
return new GraphQLHttpHandler(service);
|
||||
public GraphQLHttpHandler graphQLHttpHandler(WebGraphQLHandler webGraphQLHandler) {
|
||||
return new GraphQLHttpHandler(webGraphQLHandler);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -108,7 +106,7 @@ public class WebMvcGraphQLAutoConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public GraphQLWebSocketHandler graphQLWebSocketHandler(
|
||||
WebGraphQLService service, GraphQLProperties properties, HttpMessageConverters converters) {
|
||||
WebGraphQLHandler webGraphQLHandler, GraphQLProperties properties, HttpMessageConverters converters) {
|
||||
|
||||
HttpMessageConverter<?> converter = converters.getConverters().stream()
|
||||
.filter(candidate -> candidate.canRead(Map.class, MediaType.APPLICATION_JSON))
|
||||
@@ -116,7 +114,7 @@ public class WebMvcGraphQLAutoConfiguration {
|
||||
.orElseThrow(() -> new IllegalStateException("No JSON converter"));
|
||||
|
||||
return new GraphQLWebSocketHandler(
|
||||
service, converter, properties.getWebsocket().getConnectionInitTimeout());
|
||||
webGraphQLHandler, converter, properties.getWebsocket().getConnectionInitTimeout());
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.springframework.graphql.boot.actuate.metrics.GraphQLMetricsAutoConfiguration,\
|
||||
org.springframework.graphql.boot.GraphQLAutoConfiguration,\
|
||||
org.springframework.graphql.boot.GraphQLServiceAutoConfiguration,\
|
||||
org.springframework.graphql.boot.WebFluxGraphQLAutoConfiguration,\
|
||||
org.springframework.graphql.boot.WebMvcGraphQLAutoConfiguration
|
||||
|
||||
@@ -19,7 +19,6 @@ import java.util.Collections;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration;
|
||||
@@ -32,7 +31,6 @@ import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.graphql.web.WebInterceptor;
|
||||
import org.springframework.graphql.web.WebOutput;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
|
||||
@@ -43,7 +41,8 @@ class WebFluxApplicationContextTests {
|
||||
private static final AutoConfigurations AUTO_CONFIGURATIONS = AutoConfigurations.of(
|
||||
HttpHandlerAutoConfiguration.class, WebFluxAutoConfiguration.class,
|
||||
CodecsAutoConfiguration.class, JacksonAutoConfiguration.class,
|
||||
GraphQLAutoConfiguration.class, WebFluxGraphQLAutoConfiguration.class);
|
||||
GraphQLAutoConfiguration.class, GraphQLServiceAutoConfiguration.class,
|
||||
WebFluxGraphQLAutoConfiguration.class);
|
||||
|
||||
private static final String BASE_URL = "https://spring.example.org/graphql";
|
||||
|
||||
@@ -139,12 +138,8 @@ class WebFluxApplicationContextTests {
|
||||
|
||||
@Bean
|
||||
public WebInterceptor customWebInterceptor() {
|
||||
return new WebInterceptor() {
|
||||
@Override
|
||||
public Mono<WebOutput> postHandle(WebOutput output) {
|
||||
return Mono.just(output.transform(builder -> builder.responseHeader("X-Custom-Header", "42")));
|
||||
}
|
||||
};
|
||||
return (input, next) -> next.handle(input).map(output ->
|
||||
output.transform(builder -> builder.responseHeader("X-Custom-Header", "42")));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ package org.springframework.graphql.boot;
|
||||
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
|
||||
@@ -29,7 +28,6 @@ import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.graphql.web.WebInterceptor;
|
||||
import org.springframework.graphql.web.WebOutput;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
@@ -39,7 +37,8 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import static graphql.schema.idl.TypeRuntimeWiring.newTypeWiring;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.asyncDispatch;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@@ -48,7 +47,8 @@ class WebMvcApplicationContextTests {
|
||||
public static final AutoConfigurations AUTO_CONFIGURATIONS = AutoConfigurations.of(
|
||||
DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class, JacksonAutoConfiguration.class,
|
||||
GraphQLAutoConfiguration.class, WebMvcGraphQLAutoConfiguration.class);
|
||||
GraphQLAutoConfiguration.class, GraphQLServiceAutoConfiguration.class,
|
||||
WebMvcGraphQLAutoConfiguration.class);
|
||||
|
||||
@Test
|
||||
void endpointHandlesGraphQLQuery() {
|
||||
@@ -135,13 +135,8 @@ class WebMvcApplicationContextTests {
|
||||
|
||||
@Bean
|
||||
public WebInterceptor customWebInterceptor() {
|
||||
return new WebInterceptor() {
|
||||
@Override
|
||||
public Mono<WebOutput> postHandle(WebOutput output) {
|
||||
return Mono.just(output.transform(builder ->
|
||||
builder.responseHeader("X-Custom-Header", "42")));
|
||||
}
|
||||
};
|
||||
return (input, next) -> next.handle(input).map(output ->
|
||||
output.transform(builder -> builder.responseHeader("X-Custom-Header", "42")));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user