From 10abd919ecba6396c7940ca454d2b28148789448 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Mon, 10 Jan 2022 17:05:23 +0100 Subject: [PATCH] Configure WebSocket transport with GraphiQL This commit enhances the GraphiQL `index.html` to rely in the graphiql-tools fetcher function; this supports both HTTP and WebSocket transports. As a follow-up, this also updates the `GraphiQlHandler` implementations to also send a `wsPath` query param if a specific path has been configured for the WebSocket support. As an additional change, this commit also improves the fix for gh-231 as it was incomplete: the generated query params were not taking the context path into account. Closes gh-131 Closes gh-231 --- .../graphql/web/webflux/GraphiQlHandler.java | 28 ++++++- .../graphql/web/webmvc/GraphiQlHandler.java | 35 ++++++-- .../src/main/resources/graphiql/index.html | 79 ++++--------------- .../web/webflux/GraphiQlHandlerTests.java | 17 +++- .../web/webmvc/GraphiQlHandlerTests.java | 20 ++++- 5 files changed, 101 insertions(+), 78 deletions(-) diff --git a/spring-graphql/src/main/java/org/springframework/graphql/web/webflux/GraphiQlHandler.java b/spring-graphql/src/main/java/org/springframework/graphql/web/webflux/GraphiQlHandler.java index 820b4213..d9a0a06f 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/web/webflux/GraphiQlHandler.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/web/webflux/GraphiQlHandler.java @@ -23,8 +23,10 @@ import reactor.core.publisher.Mono; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.http.MediaType; +import org.springframework.util.StringUtils; import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.reactive.function.server.ServerResponse; +import org.springframework.web.util.UriBuilder; /** * Spring WebFlux handler to serve a GraphiQl UI page. @@ -37,6 +39,8 @@ public class GraphiQlHandler { private final String graphQlPath; + private final String graphQlWsPath; + private final Resource htmlResource; @@ -44,18 +48,21 @@ public class GraphiQlHandler { * Constructor that serves the default {@code graphiql/index.html} included * in the {@code spring-graphql} module. * @param graphQlPath the path to the GraphQL endpoint + * @param graphQlWsPath optional path to the GraphQL WebSocket endpoint */ - public GraphiQlHandler(String graphQlPath) { - this(graphQlPath, new ClassPathResource("graphiql/index.html")); + public GraphiQlHandler(String graphQlPath, String graphQlWsPath) { + this(graphQlPath, graphQlWsPath, new ClassPathResource("graphiql/index.html")); } /** * Constructor with the HTML page to serve. * @param graphQlPath the path to the GraphQL endpoint + * @param graphQlWsPath optional path to the GraphQL WebSocket endpoint * @param htmlResource the GraphiQL page to serve */ - public GraphiQlHandler(String graphQlPath, Resource htmlResource) { + public GraphiQlHandler(String graphQlPath, String graphQlWsPath, Resource htmlResource) { this.graphQlPath = graphQlPath; + this.graphQlWsPath = graphQlWsPath; this.htmlResource = htmlResource; } @@ -71,7 +78,20 @@ public class GraphiQlHandler { } private URI getRedirectUrl(ServerRequest request) { - return request.uriBuilder().queryParam("path", this.graphQlPath).build(); + UriBuilder builder = request.uriBuilder(); + String pathQueryParam = applyContextPath(request, this.graphQlPath); + builder.queryParam("path", pathQueryParam); + + if (StringUtils.hasText(this.graphQlWsPath)) { + String wsPathQueryParam = applyContextPath(request, this.graphQlWsPath); + builder.queryParam("wsPath", wsPathQueryParam); + } + return builder.build(); + } + + private String applyContextPath(ServerRequest request, String path) { + String contextPath = request.requestPath().contextPath().toString(); + return StringUtils.hasText(contextPath) ? contextPath + path : path; } } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/web/webmvc/GraphiQlHandler.java b/spring-graphql/src/main/java/org/springframework/graphql/web/webmvc/GraphiQlHandler.java index 6f57c6e0..018e6c15 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/web/webmvc/GraphiQlHandler.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/web/webmvc/GraphiQlHandler.java @@ -21,8 +21,11 @@ import java.net.URI; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.http.MediaType; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; import org.springframework.web.servlet.function.ServerRequest; import org.springframework.web.servlet.function.ServerResponse; +import org.springframework.web.util.UriBuilder; /** * Spring MVC handler to serve a GraphiQl UI page. @@ -35,25 +38,31 @@ public class GraphiQlHandler { private final String graphQlPath; + private final String graphQlWsPath; + private final Resource htmlResource; /** * Constructor that serves the default {@code graphiql/index.html} included * in the {@code spring-graphql} module. - * @param graphQlPath the path to the GraphQL endpoint + * @param graphQlPath the path to the GraphQL HTTP endpoint + * @param graphQlWsPath optional path to the GraphQL WebSocket endpoint */ - public GraphiQlHandler(String graphQlPath) { - this(graphQlPath, new ClassPathResource("graphiql/index.html")); + public GraphiQlHandler(String graphQlPath, String graphQlWsPath) { + this(graphQlPath, graphQlWsPath, new ClassPathResource("graphiql/index.html")); } /** * Constructor with the HTML page to serve. - * @param graphQlPath the path to the GraphQL endpoint + * @param graphQlPath the path to the GraphQL HTTP endpoint + * @param graphQlWsPath optional path to the GraphQL WebSocket endpoint * @param htmlResource the GraphiQL page to serve */ - public GraphiQlHandler(String graphQlPath, Resource htmlResource) { + public GraphiQlHandler(String graphQlPath, String graphQlWsPath, Resource htmlResource) { + Assert.hasText(graphQlPath, "graphQlPath should not be empty"); this.graphQlPath = graphQlPath; + this.graphQlWsPath = graphQlWsPath; this.htmlResource = htmlResource; } @@ -71,7 +80,21 @@ public class GraphiQlHandler { private URI getRedirectUrl(ServerRequest request) { String contextPath = request.requestPath().contextPath().toString(); String path = request.requestPath().pathWithinApplication().toString(); - return request.uriBuilder().replacePath(contextPath).path(path).queryParam("path", this.graphQlPath).build(); + UriBuilder builder = request.uriBuilder().replacePath(contextPath).path(path); + + String pathQueryParam = applyContextPath(request, this.graphQlPath); + builder.queryParam("path", pathQueryParam); + + if (StringUtils.hasText(this.graphQlWsPath)) { + String wsPathQueryParam = applyContextPath(request, this.graphQlWsPath); + builder.queryParam("wsPath", wsPathQueryParam); + } + return builder.build(); + } + + private String applyContextPath(ServerRequest request, String path) { + String contextPath = request.requestPath().contextPath().toString(); + return StringUtils.hasText(contextPath) ? contextPath + path : path; } } diff --git a/spring-graphql/src/main/resources/graphiql/index.html b/spring-graphql/src/main/resources/graphiql/index.html index cd47657c..bf1dbee9 100644 --- a/spring-graphql/src/main/resources/graphiql/index.html +++ b/spring-graphql/src/main/resources/graphiql/index.html @@ -1,18 +1,3 @@ - @@ -28,61 +13,29 @@ height: 100vh; } - - - - - - + +
Loading...
- +