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

Voyager configuration options #600

Merged
merged 7 commits into from
May 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 61 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,16 @@ and join the team!
- [Enable GraphQL Servlet](#enable-graphql-servlet)
- [Enable Graph*i*QL](#enable-graphiql)
- [Enable Altair](#enable-altair)
- [Enable GraphQL Playground](#enable-graphql-playground)
- [Enable GraphQL Playground](#enable-graphql-voyager)
- [Basic settings](#basic-settings)
- [CDN](#cdn)
- [Custom static resources](#custom-static-resources)
- [Customizing GraphQL Playground](#customizing-graphql-playground)
- [Tabs](#tabs)
- [Enable GraphQL Voyager](#enable-graphql-playground)
- [Basic settings](#graphql-voyager-basic-settings)
- [CDN](#graphql-voyager-cdn)
- [Customizing GraphQL Voyager](#customizing-graphql-voyager)
- [Supported GraphQL-Java Libraries](#supported-graphql-java-libraries)
- [GraphQL Java Tools](#graphql-java-tools)
- [GraphQL Annotations](#graphql-annotations)
Expand Down Expand Up @@ -433,6 +437,62 @@ You can configure the query, variables, headers and even supply sample responses
, `variables` and `responses` are expected to be resources of the appropriate format (GraphQL
for `query`, JSON for `variables` and `responses`).


# Enable GraphQL Voyager

**GraphQL Voyager** becomes accessible at root `/voyager` (or as configured
in `voyager.mapping`)
if `voyager-spring-boot-starter` is added as a dependency to a boot application.

Available Spring Boot configuration parameters (either `application.yml`
or `application.properties`):

```yaml
voyager:
enabled: true
basePath: /
mapping: /voyager
endpoint: /graphql
cdn:
enabled: false
version: latest
pageTitle: Voyager
displayOptions:
skipRelay: true
skipDeprecated: true
rootType: Query
sortByAlphabet: false
showLeafFields: true
hideRoot: false
hideDocs: false
hideSettings: false
```

## GraphQL Voyager Basic settings

`mapping` and `endpoint` will default to `/voyager` and `/graphql`, respectively. Note that these values may not be empty.

`enabled` defaults to `true`, and therefor **GraphQL Voyager** will be available by default if the dependency
is added to a Spring Boot Web Application project.

`pageTitle` defaults to `Voyager`.

All other properties default to the same as documented on the official [GraphQL Voyager readme](https://github.com/APIs-guru/graphql-voyager#properties)

## GraphQL Voyager CDN

The currently bundled version is `1.0.0-rc31`, which is - as of writing this - the latest release
of **GraphQL Voyager**. The CDN option uses `jsDelivr` CDN, if enabled. By default, it will
load the latest available release. Available CDN versions can be found on the project's
[jsDelivr page](https://www.jsdelivr.com/package/npm/graphql-voyager). The CDN option is
disabled by default.

## Customizing GraphQL Voyager

Further **GraphQL Voyager** `displayOptions`, `hideDocs` and `hideSettings` customizations can be configured, as documented in the official
[GraphQL Voyager readme](https://github.com/APIs-guru/graphql-voyager#properties).


# Supported GraphQL-Java Libraries

The following libraries have auto-configuration classes for creating a `GraphQLSchema`.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package graphql.kickstart.voyager.boot;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
Expand All @@ -16,11 +16,9 @@
@Configuration
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
@ConditionalOnProperty(value = "voyager.enabled", havingValue = "true", matchIfMissing = true)
@EnableConfigurationProperties(VoyagerPropertiesConfiguration.class)
public class ReactiveVoyagerAutoConfiguration {

@Value("${voyager.mapping:/voyager}")
private String voyagerPath;

@Bean
ReactiveVoyagerController voyagerController() {
return new ReactiveVoyagerController();
Expand All @@ -35,7 +33,7 @@ public RouterFunction<ServerResponse> voyagerStaticFilesRouter() {
}

@Bean
VoyagerIndexHtmlTemplate voyagerIndexHtmlTemplate() {
return new VoyagerIndexHtmlTemplate();
VoyagerIndexHtmlTemplate voyagerIndexHtmlTemplate(final VoyagerPropertiesConfiguration voyagerPropertiesConfiguration) {
return new VoyagerIndexHtmlTemplate(voyagerPropertiesConfiguration);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.io.IOException;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
Expand All @@ -13,6 +14,7 @@
* @author Max David Günther
*/
@Controller
@RequiredArgsConstructor
public class ReactiveVoyagerController {

@Autowired
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

Expand All @@ -11,6 +12,7 @@
@Configuration
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnProperty(value = "voyager.enabled", havingValue = "true", matchIfMissing = true)
@EnableConfigurationProperties(VoyagerPropertiesConfiguration.class)
public class VoyagerAutoConfiguration {

@Bean
Expand All @@ -19,7 +21,7 @@ VoyagerController voyagerController() {
}

@Bean
VoyagerIndexHtmlTemplate voyagerIndexHtmlTemplate() {
return new VoyagerIndexHtmlTemplate();
VoyagerIndexHtmlTemplate voyagerIndexHtmlTemplate(final VoyagerPropertiesConfiguration voyagerPropertiesConfiguration) {
return new VoyagerIndexHtmlTemplate(voyagerPropertiesConfiguration);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,70 +4,73 @@
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringSubstitutor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.RequestParam;

/**
* @author Guilherme Blanco
*/
@RequiredArgsConstructor
public class VoyagerIndexHtmlTemplate {

private static final String CDNJS_CLOUDFLARE_COM_AJAX_LIBS = "//cdnjs.cloudflare.com/ajax/libs/";
private static final String CDN_JSDELIVR_NET_NPM = "//cdn.jsdelivr.net/npm/";
private static final String VOYAGER = "graphql-voyager";
private static final String FAVICON_APIS_GURU = "//apis.guru/graphql-voyager/icons/favicon-16x16.png";

@Value("${voyager.endpoint:/graphql}")
private String graphqlEndpoint;

@Value("${voyager.pageTitle:Voyager}")
private String pageTitle;

@Value("${voyager.static.basePath:/}")
private String staticBasePath;

@Value("${voyager.cdn.enabled:false}")
private boolean voyagerCdnEnabled;

@Value("${voyager.cdn.version:1.0.0-rc.31}")
private String voyagerCdnVersion;
private final VoyagerPropertiesConfiguration voyagerConfiguration;

public String fillIndexTemplate(String contextPath, Map<String, String> params)
throws IOException {
String template = StreamUtils
.copyToString(new ClassPathResource("voyager.html").getInputStream(),
Charset.defaultCharset());

String basePath = voyagerConfiguration.getBasePath();
String voyagerCdnVersion = voyagerConfiguration.getCdn().getVersion();

Map<String, String> replacements = new HashMap<>();
replacements.put("graphqlEndpoint", constructGraphQlEndpoint(contextPath, params));
replacements.put("pageTitle", pageTitle);
replacements.put("pageTitle", voyagerConfiguration.getPageTitle());
replacements
.put("pageFavicon", getResourceUrl(staticBasePath, "favicon.ico", FAVICON_APIS_GURU));
replacements.put("es6PromiseJsUrl", getResourceUrl(staticBasePath, "es6-promise.auto.min.js",
.put("pageFavicon", getResourceUrl(basePath, "favicon.ico", FAVICON_APIS_GURU));
replacements.put("es6PromiseJsUrl", getResourceUrl(basePath, "es6-promise.auto.min.js",
joinCdnjsPath("es6-promise", "4.1.1", "es6-promise.auto.min.js")));
replacements.put("fetchJsUrl", getResourceUrl(staticBasePath, "fetch.min.js",
replacements.put("fetchJsUrl", getResourceUrl(basePath, "fetch.min.js",
joinCdnjsPath("fetch", "2.0.4", "fetch.min.js")));
replacements.put("reactJsUrl", getResourceUrl(staticBasePath, "react.min.js",
replacements.put("reactJsUrl", getResourceUrl(basePath, "react.min.js",
joinCdnjsPath("react", "16.8.3", "umd/react.production.min.js")));
replacements.put("reactDomJsUrl", getResourceUrl(staticBasePath, "react-dom.min.js",
replacements.put("reactDomJsUrl", getResourceUrl(basePath, "react-dom.min.js",
joinCdnjsPath("react-dom", "16.8.3", "umd/react-dom.production.min.js")));
replacements.put("voyagerCssUrl", getResourceUrl(staticBasePath, "voyager.css",
replacements.put("voyagerCssUrl", getResourceUrl(basePath, "voyager.css",
joinJsDelivrPath(voyagerCdnVersion, "dist/voyager.css")));
replacements.put("voyagerJsUrl", getResourceUrl(staticBasePath, "voyager.min.js",
replacements.put("voyagerJsUrl", getResourceUrl(basePath, "voyager.min.js",
joinJsDelivrPath(voyagerCdnVersion, "dist/voyager.min.js")));
replacements.put("voyagerWorkerJsUrl", getResourceUrl(staticBasePath, "voyager.worker.js",
replacements.put("voyagerWorkerJsUrl", getResourceUrl(basePath, "voyager.worker.js",
joinJsDelivrPath(voyagerCdnVersion, "dist/voyager.worker.min.js")));
replacements.put("contextPath", contextPath);
replacements.put("voyagerDisplayOptionsSkipRelay", Boolean.toString(voyagerConfiguration.getDisplayOptions().isSkipRelay()));
replacements.put("voyagerDisplayOptionsSkipDeprecated", Boolean.toString(voyagerConfiguration.getDisplayOptions().isSkipDeprecated()));
replacements.put("voyagerDisplayOptionsRootType", voyagerConfiguration.getDisplayOptions().getRootType());
replacements.put("voyagerDisplayOptionsSortByAlphabet", Boolean.toString(
voyagerConfiguration.getDisplayOptions().isSortByAlphabet()));
replacements.put("voyagerDisplayOptionsShowLeafFields", Boolean.toString(voyagerConfiguration.getDisplayOptions().isShowLeafFields()));
replacements.put("voyagerDisplayOptionsHideRoot", Boolean.toString(voyagerConfiguration.getDisplayOptions().isHideRoot()));
replacements.put("voyagerHideDocs", Boolean.toString(voyagerConfiguration.isHideDocs()));
replacements.put("voyagerHideSettings", Boolean.toString(voyagerConfiguration.isHideSettings()));



return StringSubstitutor.replace(template, replacements);
}

private String constructGraphQlEndpoint(String contextPath,
@RequestParam Map<String, String> params) {
String endpoint = graphqlEndpoint;
String endpoint = voyagerConfiguration.getEndpoint();
for (Map.Entry<String, String> param : params.entrySet()) {
endpoint = endpoint.replaceAll("\\{" + param.getKey() + "}", param.getValue());
}
Expand All @@ -78,7 +81,7 @@ private String constructGraphQlEndpoint(String contextPath,
}

private String getResourceUrl(String staticBasePath, String staticFileName, String cdnUrl) {
if (voyagerCdnEnabled && StringUtils.isNotBlank(cdnUrl)) {
if (voyagerConfiguration.getCdn().isEnabled() && StringUtils.isNotBlank(cdnUrl)) {
return cdnUrl;
}
return joinStaticPath(staticBasePath, staticFileName);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package graphql.kickstart.voyager.boot;

import com.fasterxml.jackson.annotation.JsonIgnore;
import graphql.kickstart.voyager.boot.properties.VoyagerCdn;
import graphql.kickstart.voyager.boot.properties.VoyagerDisplayOptions;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.springframework.validation.annotation.Validated;


@Data
@ConfigurationProperties(prefix = "voyager")
@Validated
public class VoyagerPropertiesConfiguration {

private String endpoint = "/graphql";

private String pageTitle = "Voyager";

private String basePath = "/";

@NestedConfigurationProperty
@JsonIgnore
private VoyagerCdn cdn = new VoyagerCdn();

@NestedConfigurationProperty
@JsonIgnore
private VoyagerDisplayOptions displayOptions = new VoyagerDisplayOptions();

@JsonIgnore
private boolean hideDocs;

@JsonIgnore
private boolean hideSettings;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package graphql.kickstart.voyager.boot.properties;

import lombok.Data;

@Data
public class VoyagerCdn {

private boolean enabled;
private String version = "latest";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package graphql.kickstart.voyager.boot.properties;

import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;

@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class VoyagerDisplayOptions {

private boolean skipRelay = true;
private boolean skipDeprecated = true;
private String rootType = "Query";
private boolean sortByAlphabet = false;
private boolean showLeafFields = true;
private boolean hideRoot = false;

}
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,15 @@ <h1> Transmitting... </h1>
GraphQLVoyager.init(document.getElementById('voyager'), {
introspection: introspectionProvider,
displayOptions: {
sortByAlphabet: true,
}
skipRelay: ${voyagerDisplayOptionsSkipRelay},
skipDeprecated: ${voyagerDisplayOptionsSkipDeprecated},
rootType: '${voyagerDisplayOptionsRootType}',
sortByAlphabet: ${voyagerDisplayOptionsSortByAlphabet},
showLeafFields: ${voyagerDisplayOptionsShowLeafFields},
hideRoot: ${voyagerDisplayOptionsHideRoot},
},
hideDocs: ${voyagerHideDocs},
hideSettings: ${voyagerHideSettings},
})
</script>
</body>
Expand Down