Skip to content
This repository was archived by the owner on Dec 19, 2023. It is now read-only.

Commit c94fdf0

Browse files
authored
Merge pull request #355 from maxdavidguenther/master
Voyager now supports webflux
2 parents 8ce945e + e9e2169 commit c94fdf0

File tree

13 files changed

+355
-79
lines changed

13 files changed

+355
-79
lines changed

example-webflux/LICENSE.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2016 Oembedler Inc. and Contributors
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6+
7+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8+
9+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

example-webflux/build.gradle

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2016 oEmbedler Inc. and Contributors
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
7+
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
8+
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
9+
* persons to whom the Software is furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
12+
*
13+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
14+
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
16+
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
17+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
18+
*/
19+
buildscript {
20+
repositories {
21+
maven { url "https://plugins.gradle.org/m2/" }
22+
maven { url 'https://repo.spring.io/plugins-release' }
23+
}
24+
dependencies {
25+
classpath("org.springframework.boot:spring-boot-gradle-plugin:$LIB_SPRING_BOOT_VER")
26+
classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:1.6"
27+
}
28+
}
29+
30+
apply plugin: 'java'
31+
apply plugin: 'org.springframework.boot'
32+
33+
repositories {
34+
mavenLocal()
35+
jcenter()
36+
}
37+
38+
dependencies {
39+
compile(project(":graphql-kickstart-spring-boot-autoconfigure-webflux"))
40+
compile(project(":graphql-kickstart-spring-boot-autoconfigure-tools"))
41+
compile(project(":voyager-spring-boot-starter"))
42+
43+
compile("org.springframework.boot:spring-boot-starter-webflux:$LIB_SPRING_BOOT_VER")
44+
compile("org.springframework.boot:spring-boot-starter-actuator:$LIB_SPRING_BOOT_VER")
45+
}
46+
47+
jar.enabled = false
48+
uploadArchives.enabled = false
49+
bintrayUpload.enabled = false
50+
install.enabled = false
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2016 oEmbedler Inc. and Contributors
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
7+
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
8+
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
9+
* persons to whom the Software is furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
12+
*
13+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
14+
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
16+
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
17+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
18+
*/
19+
20+
package com.oembedler.moon.graphql.boot.sample;
21+
22+
import graphql.Scalars;
23+
import graphql.schema.GraphQLObjectType;
24+
import graphql.schema.GraphQLSchema;
25+
import org.springframework.boot.SpringApplication;
26+
import org.springframework.boot.autoconfigure.SpringBootApplication;
27+
import org.springframework.context.annotation.Bean;
28+
import org.springframework.web.reactive.config.EnableWebFlux;
29+
30+
/**
31+
* @author Max Günther
32+
*/
33+
@SpringBootApplication
34+
@EnableWebFlux
35+
public class ApplicationWebfluxConfiguration {
36+
37+
public static void main(String[] args) {
38+
SpringApplication.run(ApplicationWebfluxConfiguration.class, args);
39+
}
40+
41+
@Bean
42+
GraphQLSchema schema() {
43+
return GraphQLSchema.newSchema()
44+
.query(GraphQLObjectType.newObject()
45+
.name("query")
46+
.field(field -> field
47+
.name("test")
48+
.type(Scalars.GraphQLString)
49+
.dataFetcher(environment -> "response")
50+
)
51+
.build())
52+
.build();
53+
}
54+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
spring:
2+
application:
3+
name: graphql-todo-app
4+
server:
5+
port: 9000
6+
management:
7+
endpoints:
8+
web:
9+
exposure:
10+
include: health,info,metrics
11+
voyager:
12+
enabled: true
13+
cdn:
14+
enabled: false

settings.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ include ":example-spring-common"
4444
include ':example-graphql-tools'
4545
include ':example-graphql-subscription'
4646
include ':example-request-scoped-dataloader'
47+
include ":example-webflux"
4748

4849
include ':graphql-spring-boot-test'
4950
include ':graphql-spring-boot-test-autoconfigure'

voyager-spring-boot-autoconfigure/build.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,12 @@ dependencies{
2121

2222
compile "org.springframework.boot:spring-boot-autoconfigure:$LIB_SPRING_BOOT_VER"
2323
compile "org.apache.commons:commons-text:1.1"
24+
2425
compileOnly "org.springframework.boot:spring-boot-starter-web:$LIB_SPRING_BOOT_VER"
26+
compileOnly "org.springframework.boot:spring-boot-starter-webflux:$LIB_SPRING_BOOT_VER"
2527

2628
testCompile "org.springframework.boot:spring-boot-starter-web:$LIB_SPRING_BOOT_VER"
29+
testCompile "org.springframework.boot:spring-boot-starter-webflux:$LIB_SPRING_BOOT_VER"
2730
testCompile "org.springframework.boot:spring-boot-starter-test:$LIB_SPRING_BOOT_VER"
2831
}
2932

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.oembedler.moon.voyager.boot;
2+
3+
import org.springframework.beans.factory.annotation.Value;
4+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
5+
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
6+
import org.springframework.context.annotation.Bean;
7+
import org.springframework.context.annotation.Configuration;
8+
import org.springframework.core.io.ClassPathResource;
9+
import org.springframework.web.reactive.function.server.RouterFunction;
10+
import org.springframework.web.reactive.function.server.RouterFunctions;
11+
import org.springframework.web.reactive.function.server.ServerResponse;
12+
13+
/**
14+
* @author Max David Günther
15+
*/
16+
@Configuration
17+
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
18+
@ConditionalOnProperty(value = "voyager.enabled", havingValue = "true", matchIfMissing = true)
19+
public class ReactiveVoyagerAutoConfiguration {
20+
21+
@Value("${voyager.mapping:/voyager}")
22+
private String voyagerPath;
23+
24+
@Bean
25+
ReactiveVoyagerController voyagerController() {
26+
return new ReactiveVoyagerController();
27+
}
28+
29+
@Bean
30+
public RouterFunction<ServerResponse> voyagerStaticFilesRouter() {
31+
return RouterFunctions.resources(
32+
"/vendor/voyager/**",
33+
new ClassPathResource("static/vendor/voyager/")
34+
);
35+
}
36+
37+
@Bean
38+
VoyagerIndexHtmlTemplate voyagerIndexHtmlTemplate() {
39+
return new VoyagerIndexHtmlTemplate();
40+
}
41+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.oembedler.moon.voyager.boot;
2+
3+
import org.springframework.beans.factory.annotation.Autowired;
4+
import org.springframework.http.MediaType;
5+
import org.springframework.http.ResponseEntity;
6+
import org.springframework.stereotype.Controller;
7+
import org.springframework.web.bind.annotation.GetMapping;
8+
9+
import java.io.IOException;
10+
11+
/**
12+
* @author Max David Günther
13+
*/
14+
@Controller
15+
public class ReactiveVoyagerController {
16+
@Autowired
17+
private VoyagerIndexHtmlTemplate indexTemplate;
18+
19+
@GetMapping(path = "${voyager.mapping:/voyager}")
20+
public ResponseEntity<String> voyager() throws IOException {
21+
// no context path in spring-webflux
22+
String indexHtmlContent = indexTemplate.fillIndexTemplate("");
23+
return ResponseEntity.ok()
24+
.contentType(MediaType.valueOf("text/html; charset=UTF-8"))
25+
.body(indexHtmlContent);
26+
}
27+
}
Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,25 @@
11
package com.oembedler.moon.voyager.boot;
22

3-
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
43
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
54
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
65
import org.springframework.context.annotation.Bean;
76
import org.springframework.context.annotation.Configuration;
8-
import org.springframework.web.servlet.DispatcherServlet;
97

108
/**
119
* @author Guilherme Blanco
1210
*/
1311
@Configuration
14-
@ConditionalOnWebApplication
15-
@ConditionalOnClass(DispatcherServlet.class)
12+
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
13+
@ConditionalOnProperty(value = "voyager.enabled", havingValue = "true", matchIfMissing = true)
1614
public class VoyagerAutoConfiguration
1715
{
1816
@Bean
19-
@ConditionalOnProperty(value = "voyager.enabled", havingValue = "true", matchIfMissing = true)
2017
VoyagerController voyagerController() {
2118
return new VoyagerController();
2219
}
20+
21+
@Bean
22+
VoyagerIndexHtmlTemplate voyagerIndexHtmlTemplate() {
23+
return new VoyagerIndexHtmlTemplate();
24+
}
2325
}
Lines changed: 11 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,28 @@
11
package com.oembedler.moon.voyager.boot;
22

3-
import org.apache.commons.lang3.StringUtils;
4-
import org.apache.commons.lang3.text.StrSubstitutor;
5-
import org.springframework.beans.factory.annotation.Value;
6-
import org.springframework.core.io.ClassPathResource;
3+
import org.springframework.beans.factory.annotation.Autowired;
4+
import org.springframework.http.MediaType;
5+
import org.springframework.http.ResponseEntity;
76
import org.springframework.stereotype.Controller;
8-
import org.springframework.util.StreamUtils;
97
import org.springframework.web.bind.annotation.RequestMapping;
108

119
import javax.servlet.http.HttpServletRequest;
12-
import javax.servlet.http.HttpServletResponse;
1310
import java.io.IOException;
14-
import java.nio.charset.Charset;
15-
import java.util.HashMap;
16-
import java.util.Map;
1711

1812
/**
19-
* @author Guilherme Blanco
13+
* @author Max David Günther
2014
*/
2115
@Controller
2216
public class VoyagerController {
23-
24-
private static final String CDNJS_CLOUDFLARE_COM_AJAX_LIBS = "//cdnjs.cloudflare.com/ajax/libs/";
25-
private static final String CDN_JSDELIVR_NET_NPM = "//cdn.jsdelivr.net/npm/";
26-
private static final String VOYAGER = "graphql-voyager";
27-
private static final String FAVICON_APIS_GURU = "//apis.guru/graphql-voyager/icons/favicon-16x16.png";
28-
29-
@Value("${voyager.endpoint:/graphql}")
30-
private String graphqlEndpoint;
31-
32-
@Value("${voyager.pageTitle:Voyager}")
33-
private String pageTitle;
34-
35-
@Value("${voyager.static.basePath:/}")
36-
private String staticBasePath;
37-
38-
@Value("${voyager.cdn.enabled:false}")
39-
private Boolean voyagerCdnEnabled;
40-
41-
@Value("${voyager.cdn.version:1.0.0-rc.26}")
42-
private String voyagerCdnVersion;
17+
@Autowired
18+
private VoyagerIndexHtmlTemplate indexTemplate;
4319

4420
@RequestMapping(value = "${voyager.mapping:/voyager}")
45-
public void voyager(HttpServletRequest request, HttpServletResponse response) throws IOException {
21+
public ResponseEntity<String> voyager(HttpServletRequest request) throws IOException {
4622
String contextPath = request.getContextPath();
47-
response.setContentType("text/html; charset=UTF-8");
48-
49-
String template = StreamUtils.copyToString(new ClassPathResource("voyager.html").getInputStream(), Charset.defaultCharset());
50-
Map<String, String> replacements = new HashMap<>();
51-
replacements.put("graphqlEndpoint", contextPath + graphqlEndpoint);
52-
replacements.put("pageTitle", pageTitle);
53-
replacements.put("pageFavicon", getResourceUrl(staticBasePath, "favicon.ico", FAVICON_APIS_GURU));
54-
replacements.put("es6PromiseJsUrl", getResourceUrl(staticBasePath, "es6-promise.auto.min.js",
55-
joinCdnjsPath("es6-promise", "4.1.1", "es6-promise.auto.min.js")));
56-
replacements.put("fetchJsUrl", getResourceUrl(staticBasePath, "fetch.min.js",
57-
joinCdnjsPath("fetch", "2.0.4", "fetch.min.js")));
58-
replacements.put("reactJsUrl", getResourceUrl(staticBasePath, "react.min.js",
59-
joinCdnjsPath("react", "16.8.3", "umd/react.production.min.js")));
60-
replacements.put("reactDomJsUrl", getResourceUrl(staticBasePath, "react-dom.min.js",
61-
joinCdnjsPath("react-dom", "16.8.3", "umd/react-dom.production.min.js")));
62-
replacements.put("voyagerCssUrl", getResourceUrl(staticBasePath, "voyager.css",
63-
joinJsDelivrPath(VOYAGER, voyagerCdnVersion, "dist/voyager.css")));
64-
replacements.put("voyagerJsUrl", getResourceUrl(staticBasePath, "voyager.min.js",
65-
joinJsDelivrPath(VOYAGER, voyagerCdnVersion, "dist/voyager.min.js")));
66-
replacements.put("voyagerWorkerJsUrl", getResourceUrl(staticBasePath, "voyager.worker.js",
67-
joinJsDelivrPath(VOYAGER, voyagerCdnVersion, "dist/voyager.worker.min.js")));
68-
replacements.put("contextPath", contextPath);
69-
70-
response.getOutputStream().write(StrSubstitutor.replace(template, replacements).getBytes(Charset.defaultCharset()));
71-
}
72-
73-
private String getResourceUrl(String staticBasePath, String staticFileName, String cdnUrl) {
74-
if (voyagerCdnEnabled && StringUtils.isNotBlank(cdnUrl)) {
75-
return cdnUrl;
76-
}
77-
return joinStaticPath(staticBasePath, staticFileName);
78-
}
79-
80-
private String joinStaticPath(String staticBasePath, String staticFileName) {
81-
return staticBasePath + "vendor/voyager/" + staticFileName;
82-
}
83-
84-
private String joinCdnjsPath(String library, String cdnVersion, String cdnFileName) {
85-
return CDNJS_CLOUDFLARE_COM_AJAX_LIBS + library + "/" + cdnVersion + "/" + cdnFileName;
86-
}
87-
88-
private String joinJsDelivrPath(String library, String cdnVersion, String cdnFileName) {
89-
return CDN_JSDELIVR_NET_NPM + library + "@" + cdnVersion + "/" + cdnFileName;
23+
String indexHtmlContent = indexTemplate.fillIndexTemplate(contextPath);
24+
return ResponseEntity.ok()
25+
.contentType(MediaType.valueOf("text/html; charset=UTF-8"))
26+
.body(indexHtmlContent);
9027
}
9128
}

0 commit comments

Comments
 (0)