Enable WebSocket endpoint with config property
Prior to this commit, the WebSocket endpoint (MVC or WebFlux) would be enabled by default. In the case of MVC, the presence of `spring-websocket` and the required dependencies was an additional hint that could enable/disable this support depending on the application. This commit changes the websocket path configuration so that it doesn't hold a default value anymore. Configuring this property will trigger the WebSocket support. Right now developers cannot configure it to be the same as the `spring.graphql.path`, but this will be solved in #30. This commit also revisits the configuration properties namespace for clarity, moving the websocket bits under their own section. Closes gh-31
This commit is contained in:
17
README.md
17
README.md
@@ -128,6 +128,23 @@ management.metrics.graphql.autotime.enabled=true
|
||||
|
||||
You can contribute `RuntimeWiringCustomizer` beans to the context in order to configure the runtime wiring of your GraphQL application.
|
||||
|
||||
### WebSocket support
|
||||
|
||||
This project also supports WebSocket as a transport for GraphQL requests - you can use it to build [`Subscription` queries](http://spec.graphql.org/draft/#sec-Subscription).
|
||||
This use case is powered by Reactor `Flux`, check out the `samples/webflux-websocket` sample application for more.
|
||||
|
||||
To enable this support, you need to configure the `spring.graphql.websocket.path` property in your application
|
||||
and have the required dependencies on classpath. In the case of a Servlet application, adding the `spring-boot-starter-websocket` should be enough.
|
||||
|
||||
WebSocket support comes with dedicated properties:
|
||||
|
||||
````properties
|
||||
# Path of the GraphQL WebSocket subscription endpoint.
|
||||
spring.graphql.websocket.path=/graphql/websocket
|
||||
# Time within which the initial {@code CONNECTION_INIT} type message must be received.
|
||||
spring.graphql.websocket.connection-init-timeout=60s
|
||||
````
|
||||
|
||||
### Extension points
|
||||
|
||||
You can contribute [`WebInterceptor` beans](https://github.com/spring-projects-experimental/spring-graphql/blob/master/spring-graphql-web/src/main/java/org/springframework/graphql/WebInterceptor.java)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020-2020 the original author or authors.
|
||||
* Copyright 2020-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.
|
||||
@@ -32,47 +32,54 @@ public class GraphQLProperties {
|
||||
*/
|
||||
private String path = "/graphql";
|
||||
|
||||
/**
|
||||
* Path of the GraphQL WebSocket subscription endpoint.
|
||||
*/
|
||||
private String webSocketPath = path + "/websocket";
|
||||
|
||||
/**
|
||||
* For the GraphQL over WebSocket endpoint, this is time within which the
|
||||
* initial {@code CONNECTION_INIT} type message must be received.
|
||||
*/
|
||||
private Duration connectionInitTimeoutDuration = Duration.ofSeconds(60);
|
||||
|
||||
private WebSocket websocket = new WebSocket();
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
return this.path;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public String getWebSocketPath() {
|
||||
return webSocketPath;
|
||||
}
|
||||
|
||||
public void setWebSocketPath(String webSocketPath) {
|
||||
this.webSocketPath = webSocketPath;
|
||||
}
|
||||
|
||||
public String getSchemaLocation() {
|
||||
return schemaLocation;
|
||||
return this.schemaLocation;
|
||||
}
|
||||
|
||||
public void setSchemaLocation(String schemaLocation) {
|
||||
this.schemaLocation = schemaLocation;
|
||||
}
|
||||
|
||||
public Duration getConnectionInitTimeoutDuration() {
|
||||
return this.connectionInitTimeoutDuration;
|
||||
public WebSocket getWebsocket() {
|
||||
return this.websocket;
|
||||
}
|
||||
|
||||
public void setConnectionInitTimeoutDuration(Duration connectionInitTimeoutDuration) {
|
||||
this.connectionInitTimeoutDuration = connectionInitTimeoutDuration;
|
||||
static class WebSocket {
|
||||
|
||||
/**
|
||||
* Path of the GraphQL WebSocket subscription endpoint.
|
||||
*/
|
||||
private String path;
|
||||
|
||||
/**
|
||||
* Time within which the initial {@code CONNECTION_INIT} type message must be received.
|
||||
*/
|
||||
private Duration connectionInitTimeout = Duration.ofSeconds(60);
|
||||
|
||||
public String getPath() {
|
||||
return this.path;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public Duration getConnectionInitTimeout() {
|
||||
return this.connectionInitTimeout;
|
||||
}
|
||||
|
||||
public void setConnectionInitTimeout(Duration connectionInitTimeout) {
|
||||
this.connectionInitTimeout = connectionInitTimeout;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -57,18 +58,6 @@ public class WebFluxGraphQLAutoConfiguration {
|
||||
return new GraphQLHttpHandler(graphQLBuilder.build(), interceptors.orderedStream().collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public GraphQLWebSocketHandler graphQLWebSocketHandler(
|
||||
GraphQL.Builder graphQLBuilder, GraphQLProperties properties, ServerCodecConfigurer configurer,
|
||||
ObjectProvider<WebInterceptor> interceptors) {
|
||||
|
||||
return new GraphQLWebSocketHandler(
|
||||
graphQLBuilder.build(), interceptors.orderedStream().collect(Collectors.toList()),
|
||||
configurer, properties.getConnectionInitTimeoutDuration()
|
||||
);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RouterFunction<ServerResponse> graphQLEndpoint(
|
||||
GraphQLHttpHandler handler, GraphQLProperties properties, ResourceLoader resourceLoader) {
|
||||
@@ -82,15 +71,33 @@ public class WebFluxGraphQLAutoConfiguration {
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HandlerMapping graphQLWebSocketEndpoint(
|
||||
GraphQLWebSocketHandler handler, GraphQLProperties properties) {
|
||||
@ConditionalOnProperty(prefix = "spring.graphql.websocket", name = "path")
|
||||
static class WebSocketConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public GraphQLWebSocketHandler graphQLWebSocketHandler(
|
||||
GraphQL.Builder graphQLBuilder, GraphQLProperties properties, ServerCodecConfigurer configurer,
|
||||
ObjectProvider<WebInterceptor> interceptors) {
|
||||
|
||||
return new GraphQLWebSocketHandler(
|
||||
graphQLBuilder.build(), interceptors.orderedStream().collect(Collectors.toList()),
|
||||
configurer, properties.getWebsocket().getConnectionInitTimeout()
|
||||
);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HandlerMapping graphQLWebSocketEndpoint(
|
||||
GraphQLWebSocketHandler handler, GraphQLProperties properties) {
|
||||
|
||||
String path = properties.getWebsocket().getPath();
|
||||
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
|
||||
mapping.setUrlMap(Collections.singletonMap(path, handler));
|
||||
mapping.setOrder(-1); // Ahead of annotated controllers
|
||||
return mapping;
|
||||
}
|
||||
|
||||
String path = properties.getWebSocketPath();
|
||||
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
|
||||
mapping.setUrlMap(Collections.singletonMap(path, handler));
|
||||
mapping.setOrder(-1); // Ahead of annotated controllers
|
||||
return mapping;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -80,6 +81,7 @@ public class WebMvcGraphQLAutoConfiguration {
|
||||
|
||||
|
||||
@ConditionalOnClass({ServerContainer.class, WebSocketHandler.class})
|
||||
@ConditionalOnProperty(prefix = "spring.graphql.websocket", name = "path")
|
||||
static class WebSocketConfiguration {
|
||||
|
||||
@Bean
|
||||
@@ -95,7 +97,7 @@ public class WebMvcGraphQLAutoConfiguration {
|
||||
|
||||
return new GraphQLWebSocketHandler(
|
||||
graphQLBuilder.build(), interceptors.orderedStream().collect(Collectors.toList()),
|
||||
converter, properties.getConnectionInitTimeoutDuration()
|
||||
converter, properties.getWebsocket().getConnectionInitTimeout()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -104,7 +106,7 @@ public class WebMvcGraphQLAutoConfiguration {
|
||||
WebSocketHttpRequestHandler httpRequestHandler =
|
||||
new WebSocketHttpRequestHandler(handler, new DefaultHandshakeHandler());
|
||||
|
||||
String path = properties.getWebSocketPath();
|
||||
String path = properties.getWebsocket().getPath();
|
||||
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
|
||||
mapping.setUrlMap(Collections.singletonMap(path, httpRequestHandler));
|
||||
mapping.setOrder(-1); // Ahead of annotated controllers
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
spring.graphql.websocket.path=/graphql/websocket
|
||||
management.endpoints.web.exposure.include=health,metrics,info
|
||||
logging.level.org.springframework.web=debug
|
||||
logging.level.org.springframework.http=debug
|
||||
|
||||
Reference in New Issue
Block a user