Skip to content

Commit 83f678a

Browse files
committed
Separate transports in GraphQL auto-configurations
This commit revisits the existing GraphQL configuration properties to better reflect which ones belong to specific transports. This also relaxes the Web auto-configurations to only require the `ExecutionGraphQlService` as a bean. The `GraphQlSource` is now an optional bean dependency. Closes gh-44495
1 parent e886785 commit 83f678a

File tree

7 files changed

+84
-33
lines changed

7 files changed

+84
-33
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/GraphQlProperties.java

+60-11
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.Arrays;
2121

2222
import org.springframework.boot.context.properties.ConfigurationProperties;
23+
import org.springframework.boot.context.properties.DeprecatedConfigurationProperty;
2324
import org.springframework.core.io.Resource;
2425

2526
/**
@@ -31,31 +32,35 @@
3132
@ConfigurationProperties("spring.graphql")
3233
public class GraphQlProperties {
3334

34-
/**
35-
* Path at which to expose a GraphQL request HTTP endpoint.
36-
*/
37-
private String path = "/graphql";
35+
private final Http http = new Http();
3836

3937
private final Graphiql graphiql = new Graphiql();
4038

39+
private final Rsocket rsocket = new Rsocket();
40+
4141
private final Schema schema = new Schema();
4242

43-
private final Websocket websocket = new Websocket();
43+
private final DeprecatedSse sse = new DeprecatedSse(this.http.getSse());
4444

45-
private final Rsocket rsocket = new Rsocket();
45+
private final Websocket websocket = new Websocket();
4646

47-
private final Sse sse = new Sse();
47+
public Http getHttp() {
48+
return this.http;
49+
}
4850

4951
public Graphiql getGraphiql() {
5052
return this.graphiql;
5153
}
5254

55+
@DeprecatedConfigurationProperty(replacement = "spring.graphql.http.path", since = "3.5.0")
56+
@Deprecated(since = "3.5.0", forRemoval = true)
5357
public String getPath() {
54-
return this.path;
58+
return getHttp().getPath();
5559
}
5660

61+
@Deprecated(since = "3.5.0", forRemoval = true)
5762
public void setPath(String path) {
58-
this.path = path;
63+
getHttp().setPath(path);
5964
}
6065

6166
public Schema getSchema() {
@@ -70,10 +75,33 @@ public Rsocket getRsocket() {
7075
return this.rsocket;
7176
}
7277

73-
public Sse getSse() {
78+
public DeprecatedSse getSse() {
7479
return this.sse;
7580
}
7681

82+
public static class Http {
83+
84+
/**
85+
* Path at which to expose a GraphQL request HTTP endpoint.
86+
*/
87+
private String path = "/graphql";
88+
89+
private final Sse sse = new Sse();
90+
91+
public String getPath() {
92+
return this.path;
93+
}
94+
95+
public void setPath(String path) {
96+
this.path = path;
97+
}
98+
99+
public Sse getSse() {
100+
return this.sse;
101+
}
102+
103+
}
104+
77105
public static class Schema {
78106

79107
/**
@@ -178,7 +206,7 @@ public static class Printer {
178206

179207
/**
180208
* Whether the endpoint that prints the schema is enabled. Schema is available
181-
* under spring.graphql.path + "/schema".
209+
* under spring.graphql.http.path + "/schema".
182210
*/
183211
private boolean enabled = false;
184212

@@ -302,4 +330,25 @@ public void setTimeout(Duration timeout) {
302330

303331
}
304332

333+
public static class DeprecatedSse {
334+
335+
private final Sse sse;
336+
337+
public DeprecatedSse(Sse sse) {
338+
this.sse = sse;
339+
}
340+
341+
@DeprecatedConfigurationProperty(replacement = "spring.graphql.http.sse.timeout", since = "3.5.0")
342+
@Deprecated(since = "3.5.0", forRemoval = true)
343+
public Duration getTimeout() {
344+
return this.sse.getTimeout();
345+
}
346+
347+
@Deprecated(since = "3.5.0", forRemoval = true)
348+
public void setTimeout(Duration timeout) {
349+
this.sse.setTimeout(timeout);
350+
}
351+
352+
}
353+
305354
}

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/reactive/GraphQlWebFluxAutoConfiguration.java

+13-11
Original file line numberDiff line numberDiff line change
@@ -87,28 +87,29 @@ public class GraphQlWebFluxAutoConfiguration {
8787

8888
@Bean
8989
@ConditionalOnMissingBean
90-
public WebGraphQlHandler webGraphQlHandler(ExecutionGraphQlService service,
91-
ObjectProvider<WebGraphQlInterceptor> interceptors) {
92-
return WebGraphQlHandler.builder(service).interceptors(interceptors.orderedStream().toList()).build();
90+
public GraphQlHttpHandler graphQlHttpHandler(WebGraphQlHandler webGraphQlHandler) {
91+
return new GraphQlHttpHandler(webGraphQlHandler);
9392
}
9493

9594
@Bean
9695
@ConditionalOnMissingBean
97-
public GraphQlHttpHandler graphQlHttpHandler(WebGraphQlHandler webGraphQlHandler) {
98-
return new GraphQlHttpHandler(webGraphQlHandler);
96+
public GraphQlSseHandler graphQlSseHandler(WebGraphQlHandler webGraphQlHandler, GraphQlProperties properties) {
97+
return new GraphQlSseHandler(webGraphQlHandler, properties.getHttp().getSse().getTimeout());
9998
}
10099

101100
@Bean
102101
@ConditionalOnMissingBean
103-
public GraphQlSseHandler graphQlSseHandler(WebGraphQlHandler webGraphQlHandler) {
104-
return new GraphQlSseHandler(webGraphQlHandler);
102+
public WebGraphQlHandler webGraphQlHandler(ExecutionGraphQlService service,
103+
ObjectProvider<WebGraphQlInterceptor> interceptors) {
104+
return WebGraphQlHandler.builder(service).interceptors(interceptors.orderedStream().toList()).build();
105105
}
106106

107107
@Bean
108108
@Order(0)
109109
public RouterFunction<ServerResponse> graphQlRouterFunction(GraphQlHttpHandler httpHandler,
110-
GraphQlSseHandler sseHandler, GraphQlSource graphQlSource, GraphQlProperties properties) {
111-
String path = properties.getPath();
110+
GraphQlSseHandler sseHandler, ObjectProvider<GraphQlSource> graphQlSourceProvider,
111+
GraphQlProperties properties) {
112+
String path = properties.getHttp().getPath();
112113
logger.info(LogMessage.format("GraphQL endpoint HTTP POST %s", path));
113114
RouterFunctions.Builder builder = RouterFunctions.route();
114115
builder.route(GraphQlRequestPredicates.graphQlHttp(path), httpHandler::handleRequest);
@@ -119,7 +120,8 @@ public RouterFunction<ServerResponse> graphQlRouterFunction(GraphQlHttpHandler h
119120
GraphiQlHandler graphQlHandler = new GraphiQlHandler(path, properties.getWebsocket().getPath());
120121
builder.GET(properties.getGraphiql().getPath(), graphQlHandler::handleRequest);
121122
}
122-
if (properties.getSchema().getPrinter().isEnabled()) {
123+
GraphQlSource graphQlSource = graphQlSourceProvider.getIfAvailable();
124+
if (properties.getSchema().getPrinter().isEnabled() && graphQlSource != null) {
123125
SchemaHandler schemaHandler = new SchemaHandler(graphQlSource);
124126
builder.GET(path + "/schema", schemaHandler::handleRequest);
125127
}
@@ -158,7 +160,7 @@ public GraphQlEndpointCorsConfiguration(GraphQlProperties graphQlProps, GraphQlC
158160
public void addCorsMappings(CorsRegistry registry) {
159161
CorsConfiguration configuration = this.corsProperties.toCorsConfiguration();
160162
if (configuration != null) {
161-
registry.addMapping(this.graphQlProperties.getPath()).combine(configuration);
163+
registry.addMapping(this.graphQlProperties.getHttp().getPath()).combine(configuration);
162164
}
163165
}
164166

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/servlet/GraphQlWebMvcAutoConfiguration.java

+7-7
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
import org.springframework.boot.autoconfigure.graphql.GraphQlAutoConfiguration;
3838
import org.springframework.boot.autoconfigure.graphql.GraphQlCorsProperties;
3939
import org.springframework.boot.autoconfigure.graphql.GraphQlProperties;
40-
import org.springframework.boot.autoconfigure.graphql.GraphQlProperties.Sse;
4140
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
4241
import org.springframework.boot.context.properties.EnableConfigurationProperties;
4342
import org.springframework.context.annotation.Bean;
@@ -99,8 +98,7 @@ public GraphQlHttpHandler graphQlHttpHandler(WebGraphQlHandler webGraphQlHandler
9998
@Bean
10099
@ConditionalOnMissingBean
101100
public GraphQlSseHandler graphQlSseHandler(WebGraphQlHandler webGraphQlHandler, GraphQlProperties properties) {
102-
Sse sse = properties.getSse();
103-
return new GraphQlSseHandler(webGraphQlHandler, sse.getTimeout());
101+
return new GraphQlSseHandler(webGraphQlHandler, properties.getHttp().getSse().getTimeout());
104102
}
105103

106104
@Bean
@@ -113,8 +111,9 @@ public WebGraphQlHandler webGraphQlHandler(ExecutionGraphQlService service,
113111
@Bean
114112
@Order(0)
115113
public RouterFunction<ServerResponse> graphQlRouterFunction(GraphQlHttpHandler httpHandler,
116-
GraphQlSseHandler sseHandler, GraphQlSource graphQlSource, GraphQlProperties properties) {
117-
String path = properties.getPath();
114+
GraphQlSseHandler sseHandler, ObjectProvider<GraphQlSource> graphQlSourceProvider,
115+
GraphQlProperties properties) {
116+
String path = properties.getHttp().getPath();
118117
logger.info(LogMessage.format("GraphQL endpoint HTTP POST %s", path));
119118
RouterFunctions.Builder builder = RouterFunctions.route();
120119
builder.route(GraphQlRequestPredicates.graphQlHttp(path), httpHandler::handleRequest);
@@ -125,7 +124,8 @@ public RouterFunction<ServerResponse> graphQlRouterFunction(GraphQlHttpHandler h
125124
GraphiQlHandler graphiQLHandler = new GraphiQlHandler(path, properties.getWebsocket().getPath());
126125
builder.GET(properties.getGraphiql().getPath(), graphiQLHandler::handleRequest);
127126
}
128-
if (properties.getSchema().getPrinter().isEnabled()) {
127+
GraphQlSource graphQlSource = graphQlSourceProvider.getIfAvailable();
128+
if (properties.getSchema().getPrinter().isEnabled() && graphQlSource != null) {
129129
SchemaHandler schemaHandler = new SchemaHandler(graphQlSource);
130130
builder.GET(path + "/schema", schemaHandler::handleRequest);
131131
}
@@ -164,7 +164,7 @@ public GraphQlEndpointCorsConfiguration(GraphQlProperties graphQlProps, GraphQlC
164164
public void addCorsMappings(CorsRegistry registry) {
165165
CorsConfiguration configuration = this.corsProperties.toCorsConfiguration();
166166
if (configuration != null) {
167-
registry.addMapping(this.graphQlProperties.getPath()).combine(configuration);
167+
registry.addMapping(this.graphQlProperties.getHttp().getPath()).combine(configuration);
168168
}
169169
}
170170

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/graphql/servlet/GraphQlWebMvcAutoConfigurationTests.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ void shouldContributeDefaultBeans() {
8181

8282
@Test
8383
void shouldConfigureSseTimeout() {
84-
this.contextRunner.withPropertyValues("spring.graphql.sse.timeout=10s").run((context) -> {
84+
this.contextRunner.withPropertyValues("spring.graphql.http.sse.timeout=10s").run((context) -> {
8585
assertThat(context).hasSingleBean(GraphQlSseHandler.class);
8686
GraphQlSseHandler handler = context.getBean(GraphQlSseHandler.class);
8787
assertThat(handler).hasFieldOrPropertyWithValue("timeout", Duration.ofSeconds(10));

spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/web/spring-graphql.adoc

+1-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ are detected by Spring Boot and considered as candidates for javadoc:graphql.sch
9494

9595
The GraphQL HTTP endpoint is at HTTP POST `/graphql` by default.
9696
It also supports the `"text/event-stream"` media type over Server Sent Events for subscriptions only.
97-
The path can be customized with configprop:spring.graphql.path[].
97+
The path can be customized with configprop:spring.graphql.http.path[].
9898

9999
TIP: The HTTP endpoint for both Spring MVC and Spring WebFlux is provided by a `RouterFunction` bean with an javadoc:org.springframework.core.annotation.Order[format=annotation] of `0`.
100100
If you define your own `RouterFunction` beans, you may want to add appropriate javadoc:org.springframework.core.annotation.Order[format=annotation] annotations to ensure that they are sorted correctly.

spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/graphql/tester/HttpGraphQlTesterAutoConfiguration.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public class HttpGraphQlTesterAutoConfiguration {
4343
@ConditionalOnBean(WebTestClient.class)
4444
@ConditionalOnMissingBean
4545
public HttpGraphQlTester webTestClientGraphQlTester(WebTestClient webTestClient, GraphQlProperties properties) {
46-
WebTestClient mutatedWebTestClient = webTestClient.mutate().baseUrl(properties.getPath()).build();
46+
WebTestClient mutatedWebTestClient = webTestClient.mutate().baseUrl(properties.getHttp().getPath()).build();
4747
return HttpGraphQlTester.create(mutatedWebTestClient);
4848
}
4949

spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/graphql/tester/HttpGraphQlTesterContextCustomizer.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ private String deduceBasePath() {
171171
}
172172

173173
private String findConfiguredGraphQlPath() {
174-
String configuredPath = this.applicationContext.getEnvironment().getProperty("spring.graphql.path");
174+
String configuredPath = this.applicationContext.getEnvironment().getProperty("spring.graphql.http.path");
175175
return StringUtils.hasText(configuredPath) ? configuredPath : "/graphql";
176176
}
177177

0 commit comments

Comments
 (0)