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

Commit f38599f

Browse files
committed
Merge remote-tracking branch 'origin/master'
2 parents 10bbfd0 + c4ec427 commit f38599f

File tree

57 files changed

+1189
-8
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+1189
-8
lines changed

README.md

Lines changed: 105 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,24 @@
77
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
88
**Table of Contents**
99

10-
- [GraphQL and Graph*i*QL Spring Framework Boot Starters](#graphql-and-graphiql-spring-framework-boot-starters)
1110
- [WARNING: NoClassDefFoundError when using GraphQL Java Tools > 5.4.x](#warning-noclassdeffounderror-when-using-graphql-java-tools--54x)
1211
- [Using Gradle](#using-gradle)
1312
- [Using Maven](#using-maven)
1413
- [Documentation](#documentation)
1514
- [Requirements and Downloads](#requirements-and-downloads)
1615
- [Enable GraphQL Servlet](#enable-graphql-servlet)
1716
- [Enable Graph*i*QL](#enable-graphiql)
17+
- [Enable Altair](#enable-altair)
18+
- [Enable GraphQL Playground](#enable-graphql-playground)
19+
- [Basic settings](#basic-settings)
20+
- [CDN](#cdn)
21+
- [Custom static resources](#custom-static-resources)
22+
- [Customizing GraphQL Playground](#customizing-graphql-playground)
23+
- [Tabs](#tabs)
1824
- [Supported GraphQL-Java Libraries](#supported-graphql-java-libraries)
1925
- [GraphQL Java Tools](#graphql-java-tools)
2026
- [Tracing and Metrics](#tracing-and-metrics)
27+
- [Usage](#usage)
2128
- [Contributions](#contributions)
2229
- [Licenses](#licenses)
2330

@@ -55,6 +62,7 @@ Repository contains:
5562
* `graphql-spring-boot-starter` to turn your boot application into GraphQL server (see [graphql-java-servlet](https://github.com/graphql-java-kickstart/graphql-java-servlet))
5663
* `altair-spring-boot-starter`to embed `Altair` tool for schema introspection and query debugging (see [altair](https://github.com/imolorhe/altair))
5764
* `graphiql-spring-boot-starter`to embed `GraphiQL` tool for schema introspection and query debugging (see [graphiql](https://github.com/graphql/graphiql))
65+
* `playground-spring-boot-starter`to embed `GraphQL Playground` tool for schema introspection and query debugging (see [GraphQL Playground](https://github.com/prisma/graphql-playground))
5866
* `voyager-spring-boot-starter`to embed `Voyager` tool for visually explore GraphQL APIs as an interactive graph (see [voyger](https://github.com/APIs-guru/graphql-voyager))
5967

6068
# Requirements and Downloads
@@ -251,6 +259,102 @@ to set the classpath resources that should be loaded.
251259

252260
Headers that are used when sending the Altair queries can be set by defining them in the `altair.headers` group.
253261

262+
# Enable GraphQL Playground
263+
264+
GraphQL Playground becomes accessible at root `/playground` (or as configured in `graphql.playground.mapping`)
265+
if `playground-spring-boot-starter` is added as a dependency to a boot application.
266+
267+
It uses an embedded `GraphQL Playground React`, in accordance to the [official guide](https://github.com/prisma/graphql-playground#as-html-page),
268+
using the 'minimum HTML' approach.
269+
270+
Available Spring Boot configuration parameters (either `application.yml` or `application.properties`):
271+
272+
```yaml
273+
graphql.playground:
274+
mapping: /playground
275+
endpoint: /graphql
276+
subscriptionsEndpoint: /subscriptions
277+
staticFolder.basePath: my-playground-resources-folder
278+
enabled: true
279+
pageTitle: Playground
280+
cdn:
281+
enabled: false
282+
version: latest
283+
settings:
284+
editor.cursorShape: line
285+
editor.fontFamily: "'Source Code Pro', 'Consolas', 'Inconsolata', 'Droid Sans Mono', 'Monaco', monospace"
286+
editor.fontSize: 14
287+
editor.reuseHeaders: true
288+
editor.theme: dark
289+
general.betaUpdates: false
290+
prettier.printWidth: 80
291+
prettier.tabWidth: 2
292+
prettier.useTabs: false
293+
request.credentials: omit
294+
schema.polling.enable: true
295+
schema.polling.endpointFilter: "*localhost*"
296+
schema.polling.interval: 2000
297+
schema.disableComments: true
298+
tracing.hideTracingResponse: true
299+
headers:
300+
headerFor: AllTabs
301+
tabs:
302+
- name: Example Tab
303+
query: classpath:exampleQuery.graphql
304+
headers:
305+
SomeHeader: Some value
306+
variables: classpath:variables.json
307+
responses:
308+
- classpath:exampleResponse1.json
309+
- classpath:exampleResponse2.json
310+
```
311+
## Basic settings
312+
313+
`mapping`, `endpoint` and `subscriptionsEndpoint` will default to `/playground`, `/graphql` and `/subscriptions`,
314+
respectively. Note that these values may not be empty.
315+
316+
`enabled` defaults to `true`, and therefor Playground will be available by default if the dependency is added to a
317+
Spring Boot Web Application project.
318+
319+
`pageTitle` defaults to `Playground`.
320+
321+
`headers` allows you to specify headers for the default tab. Note that if your are using Spring Security and CSRF is
322+
enabled CSRF, the CSRF token will be automatically added to the headers. These headers will also be added to all the tabs
323+
configured under the [Tabs](#tabs) section. If a header is defined both in this 'global' header list and the header list
324+
of the individual tabs, the 'local' version will be used for that tab.
325+
326+
## CDN
327+
328+
The currently bundled version is `1.7.20`, which is - as of writing this - the latest release of `GraphQL Playground React`.
329+
The CDN option uses `jsDelivr` CDN, if enabled. By default, it will load the latest available release.
330+
Available CDN versions can be found on the project's
331+
[jsDelivr page](https://www.jsdelivr.com/package/npm/graphql-playground-react). The CDN option is disabled by default.
332+
333+
## Custom static resources
334+
335+
You can also specify a custom local version of Playground by setting the base path for `Playground` resources in
336+
the `staticPath.base` property. Under this directory, you have to provide the following files:
337+
338+
* `static/css/index.css`
339+
* `static/js/middleware.js`
340+
* `favicon.png`
341+
* `logo.png`
342+
343+
This is identical to the directory structure of the CDN under the `build` subfolder (where these files can be found).
344+
345+
## Customizing GraphQL Playground
346+
347+
Further GraphQL Playground settings can be specified under the `settings` group, which are documented in the official
348+
[GraphQL Playground readme](https://github.com/prisma/graphql-playground#settings). Note that enum-like values are
349+
validated against the available options, and your application will not start if wrong settings are provided. Similarly
350+
there is some basic validation for integer values (they must be valid positive integers).
351+
352+
## Tabs
353+
354+
Optionally, you can specify tabs that will be present when the user first opens GraphQL Playground. You can configure the
355+
query, variables, headers and even supply sample responses. Note that `query`, `variables` and `responses` are expected
356+
to be resources of the appropriate format (GraphQL for `query`, JSON for `variables` and `responses`).
357+
254358
# Supported GraphQL-Java Libraries
255359

256360
The following libraries have auto-configuration classes for creating a `GraphQLSchema`.

build.gradle

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ buildscript {
2424
jcenter()
2525
maven { url "https://dl.bintray.com/graphql-java-kickstart/releases" }
2626
maven { url "https://plugins.gradle.org/m2/" }
27-
maven { url 'http://repo.spring.io/plugins-release' }
27+
maven { url 'https://repo.spring.io/plugins-release' }
2828
}
2929
dependencies {
3030
classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4"
@@ -52,8 +52,8 @@ subprojects {
5252
mavenCentral()
5353
jcenter()
5454
maven { url "https://dl.bintray.com/graphql-java-kickstart/releases" }
55-
maven { url "http://oss.jfrog.org/artifactory/oss-snapshot-local" }
56-
maven { url "http://repo.spring.io/libs-milestone" }
55+
maven { url "https://oss.jfrog.org/artifactory/oss-snapshot-local" }
56+
maven { url "https://repo.spring.io/libs-milestone" }
5757
}
5858

5959
idea {
@@ -187,7 +187,9 @@ release {
187187
'com.graphql-java-kickstart:graphql-spring-boot-test',
188188
'com.graphql-java-kickstart:graphql-spring-boot-test-autoconfigure',
189189
'com.graphql-java-kickstart:voyager-spring-boot-autoconfigure',
190-
'com.graphql-java-kickstart:voyager-spring-boot-starter'
190+
'com.graphql-java-kickstart:voyager-spring-boot-starter',
191+
'com.graphql-java-kickstart:playgroud-spring-boot-autoconfigure',
192+
'com.graphql-java-kickstart:playgroud-spring-boot-starter'
191193
]
192194
}
193195

example-spring-common/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
buildscript {
2020
repositories {
2121
maven { url "https://plugins.gradle.org/m2/" }
22-
maven { url 'http://repo.spring.io/plugins-release' }
22+
maven { url 'https://repo.spring.io/plugins-release' }
2323
}
2424
dependencies {
2525
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.2.RELEASE")

example/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
buildscript {
2020
repositories {
2121
maven { url "https://plugins.gradle.org/m2/" }
22-
maven { url 'http://repo.spring.io/plugins-release' }
22+
maven { url 'https://repo.spring.io/plugins-release' }
2323
}
2424
dependencies {
2525
classpath("org.springframework.boot:spring-boot-gradle-plugin:$LIB_SPRING_BOOT_VER")

graphql-spring-boot-test-autoconfigure/src/main/java/com/graphql/spring/boot/test/GraphQLTest.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
* <p>
6060
* If you are looking to load your full application configuration and use
6161
* {@link com.graphql.spring.boot.test.GraphQLTestTemplate GraphQLTestTemplate} you should consider
62-
* {@link SpringBootTest @SpringBootTest} rather thatn this annotation.
62+
* {@link SpringBootTest @SpringBootTest} rather than this annotation.
6363
*
6464
* @author Michiel Oliemans
6565
* @since 5.0.2
@@ -101,6 +101,11 @@ Class<?>[] classes() default {
101101
JacksonAutoConfiguration.class
102102
};
103103

104+
@AliasFor(
105+
annotation = ComponentScan.class
106+
)
107+
boolean useDefaultFilters() default false;
108+
104109
@AliasFor(
105110
annotation = ComponentScan.class
106111
)

graphql-spring-boot-test/src/main/java/com/graphql/spring/boot/test/GraphQLResponse.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ public class GraphQLResponse {
1919
public GraphQLResponse(ResponseEntity<String> responseEntity) {
2020
this.responseEntity = Objects.requireNonNull(responseEntity);
2121
this.mapper = new ObjectMapper();
22+
23+
Objects.requireNonNull(responseEntity.getBody(),
24+
() -> "Body is empty with status " + responseEntity.getStatusCodeValue());
2225
context = JsonPath.parse(responseEntity.getBody());
2326
}
2427

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.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
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+
dependencies{
20+
annotationProcessor "org.springframework.boot:spring-boot-configuration-processor:$LIB_SPRING_BOOT_VER"
21+
22+
compile "org.springframework.boot:spring-boot-autoconfigure:$LIB_SPRING_BOOT_VER"
23+
compile "org.springframework.boot:spring-boot-starter-web:$LIB_SPRING_BOOT_VER"
24+
compile "org.springframework.boot:spring-boot-starter-thymeleaf:$LIB_SPRING_BOOT_VER"
25+
26+
testCompile "org.springframework.boot:spring-boot-starter-web:$LIB_SPRING_BOOT_VER"
27+
testCompile "org.springframework.boot:spring-boot-starter-test:$LIB_SPRING_BOOT_VER"
28+
testCompile "org.springframework.boot:spring-boot-starter-security:$LIB_SPRING_BOOT_VER"
29+
testCompile "org.jsoup:jsoup:1.12.1"
30+
}
31+
32+
compileJava.dependsOn(processResources)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.oembedler.moon.playground.boot;
2+
3+
import com.fasterxml.jackson.databind.ObjectMapper;
4+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
5+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
6+
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
7+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
8+
import org.springframework.context.annotation.Bean;
9+
import org.springframework.context.annotation.Configuration;
10+
import org.springframework.web.servlet.DispatcherServlet;
11+
12+
@Configuration
13+
@ConditionalOnWebApplication
14+
@ConditionalOnClass(DispatcherServlet.class)
15+
@EnableConfigurationProperties(PlaygroundPropertiesConfiguration.class)
16+
public class PlaygroundAutoConfiguration {
17+
18+
@Bean
19+
@ConditionalOnProperty(value = "graphql.playground.enabled", havingValue = "true", matchIfMissing = true)
20+
PlaygroundController playgroundController(final PlaygroundPropertiesConfiguration playgroundPropertiesConfiguration,
21+
final ObjectMapper objectMapper) {
22+
return new PlaygroundController(playgroundPropertiesConfiguration, objectMapper);
23+
}
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package com.oembedler.moon.playground.boot;
2+
3+
import com.fasterxml.jackson.databind.ObjectMapper;
4+
import lombok.RequiredArgsConstructor;
5+
import org.springframework.stereotype.Controller;
6+
import org.springframework.ui.Model;
7+
import org.springframework.web.bind.annotation.GetMapping;
8+
9+
import javax.servlet.http.HttpServletRequest;
10+
import java.nio.file.Paths;
11+
12+
@Controller
13+
@RequiredArgsConstructor
14+
public class PlaygroundController {
15+
16+
private static final String CDN_ROOT = "https://cdn.jsdelivr.net/npm/graphql-playground-react";
17+
private static final String CSS_PATH = "static/css/index.css";
18+
private static final String FAVICON_PATH = "favicon.png";
19+
private static final String SCRIPT_PATH = "static/js/middleware.js";
20+
private static final String LOGO_PATH = "logo.png";
21+
22+
private static final String CSS_URL_ATTRIBUTE_NAME = "cssUrl";
23+
private static final String FAVICON_URL_ATTRIBUTE_NAME = "faviconUrl";
24+
private static final String SCRIPT_URL_ATTRIBUTE_NAME = "scriptUrl";
25+
private static final String LOGO_URL_ATTRIBUTE_NAME = "logoUrl";
26+
27+
private final PlaygroundPropertiesConfiguration propertiesConfiguration;
28+
29+
private final ObjectMapper objectMapper;
30+
31+
@GetMapping("${graphql.playground.mapping:/playground}")
32+
public String playground(final Model model, final HttpServletRequest request) {
33+
if (propertiesConfiguration.getPlayground().getCdn().isEnabled()) {
34+
setCdnUrls(model);
35+
} else {
36+
setLocalAssetUrls(model);
37+
}
38+
model.addAttribute("pageTitle", propertiesConfiguration.getPlayground().getPageTitle());
39+
model.addAttribute("properties", objectMapper.valueToTree(propertiesConfiguration.getPlayground()));
40+
model.addAttribute("_csrf", request.getAttribute("_csrf"));
41+
return "playground";
42+
}
43+
44+
private String getCdnUrl(final String assetPath) {
45+
return String.format("%s@%s/build/%s", CDN_ROOT, propertiesConfiguration.getPlayground().getCdn().getVersion(),
46+
assetPath);
47+
}
48+
49+
private String getLocalUrl(final String assetPath) {
50+
return Paths.get(propertiesConfiguration.getPlayground().getStaticPath().getBase(), assetPath).toString()
51+
.replace('\\', '/');
52+
}
53+
54+
private void setCdnUrls(final Model model) {
55+
model.addAttribute(CSS_URL_ATTRIBUTE_NAME, getCdnUrl(CSS_PATH));
56+
model.addAttribute(FAVICON_URL_ATTRIBUTE_NAME, getCdnUrl(FAVICON_PATH));
57+
model.addAttribute(SCRIPT_URL_ATTRIBUTE_NAME, getCdnUrl(SCRIPT_PATH));
58+
model.addAttribute(LOGO_URL_ATTRIBUTE_NAME, getCdnUrl(LOGO_PATH));
59+
}
60+
61+
private void setLocalAssetUrls(final Model model) {
62+
model.addAttribute(CSS_URL_ATTRIBUTE_NAME, getLocalUrl(CSS_PATH));
63+
model.addAttribute(FAVICON_URL_ATTRIBUTE_NAME, getLocalUrl(FAVICON_PATH));
64+
model.addAttribute(SCRIPT_URL_ATTRIBUTE_NAME, getLocalUrl(SCRIPT_PATH));
65+
model.addAttribute(LOGO_URL_ATTRIBUTE_NAME, getLocalUrl(LOGO_PATH));
66+
}
67+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.oembedler.moon.playground.boot;
2+
3+
import com.oembedler.moon.playground.boot.properties.PlaygroundProperties;
4+
import lombok.Data;
5+
import org.springframework.boot.context.properties.ConfigurationProperties;
6+
import org.springframework.boot.context.properties.NestedConfigurationProperty;
7+
import org.springframework.validation.annotation.Validated;
8+
9+
@Data
10+
@ConfigurationProperties(prefix = "graphql")
11+
@Validated
12+
public class PlaygroundPropertiesConfiguration {
13+
14+
@NestedConfigurationProperty
15+
private PlaygroundProperties playground = new PlaygroundProperties();
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.oembedler.moon.playground.boot;
2+
3+
import com.fasterxml.jackson.core.JsonGenerator;
4+
import com.fasterxml.jackson.databind.JsonSerializer;
5+
import com.fasterxml.jackson.databind.SerializerProvider;
6+
import org.apache.tomcat.util.http.fileupload.util.Streams;
7+
import org.springframework.boot.jackson.JsonComponent;
8+
import org.springframework.core.io.Resource;
9+
10+
import java.io.IOException;
11+
import java.nio.charset.StandardCharsets;
12+
13+
@JsonComponent
14+
public class ResourceSerializer extends JsonSerializer<Resource> {
15+
@Override
16+
public void serialize(final Resource value, final JsonGenerator gen, final SerializerProvider serializers)
17+
throws IOException {
18+
final String content = Streams.asString(value.getInputStream(), StandardCharsets.UTF_8.name());
19+
gen.writeString(content);
20+
}
21+
}

0 commit comments

Comments
 (0)