Skip to content

Commit

Permalink
GraphiQL separate module
Browse files Browse the repository at this point in the history
- Drop existing single page cdn integration from boot project.
- Create new spring-graphql-graphiql module containing graphiql integration.
- Makes graphiql optional which user can pull in as a dependency.
- spring-graphql-graphiql is a basic npm module which packages itself as
  a jar where boot autoconfig can integrate to.
- In a npm module graphiql itself is handled as a plain react app which allows
  some customisation like setting logo name to demonstrate how things are passed
  from boot properties into a react app itself.
- GraphiQlHandler's are changed to handle all traffic into `/graphiql` order to:
  - Handling main html in `/graphiql/explorer`
  - Redirect to `/graphiql/explorer` to get context path under `/graphiql/`
  - Handle `main.js` from classpath to get html to load it under `/graphiql/`
  - Handle `config.js` as a way to pass configuration options from server side
    and load those into react app which is based on long discussion in
    facebook/create-react-app#2353 to overcome issues
    not hardcoding things on a compile time.
- Samples webmvc-http and webflux-websocket is changed to use this module.
  - webmvc-http is as it used to be.
  - webflux-websocket can now use subcription which gets first greeting instead
    of subscribtion request reply.

This is a draft POC, so tests and more work to npm project would be added
later to polish things a bit. Bundle via webpack is way too big right now
and didn't yet figure out why tree shaking don't work better.

This is a based on some of my old hacks I experimented with graphiql and
if looking promising would then give better foundation to think about
security and other things we'd like to have on this layer. Having a full
blown module and react code in typescript makes it easier to tweak things
instead of trying to rely on public stuff on cdn as a static app relying on
an internet access.

With `webmvc-http` you can use:

```
query {
  greeting
}
```

With `webflux-websocket` you can use both:

```
query {
  greeting
}

subscription {
  greetings
}
```
  • Loading branch information
jvalkeal committed Nov 26, 2021
1 parent cc5a842 commit a6c403e
Show file tree
Hide file tree
Showing 20 changed files with 8,568 additions and 124 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,11 @@ public static class GraphiQL {
*/
private boolean enabled = true;

/**
* GraphiQL logo string
*/
private String logo = "GraphiQL";

public String getPath() {
return this.path;
}
Expand All @@ -148,6 +153,14 @@ public boolean isEnabled() {
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}

public String getLogo() {
return logo;
}

public void setLogo(String logo) {
this.logo = logo;
}
}

public static class Websocket {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
package org.springframework.graphql.boot;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

import graphql.GraphQL;
Expand Down Expand Up @@ -108,9 +110,13 @@ public RouterFunction<ServerResponse> graphQlEndpoint(GraphQlHttpHandler handler
handler::handleRequest);

if (properties.getGraphiql().isEnabled()) {
Resource resource = resourceLoader.getResource("classpath:graphiql/index.html");
GraphiQlHandler graphiQlHandler = new GraphiQlHandler(graphQLPath, resource);
builder = builder.GET(properties.getGraphiql().getPath(), graphiQlHandler::handleRequest);
Resource htmlResource = resourceLoader.getResource("classpath:graphiql/index.html");
Resource jsResource = resourceLoader.getResource("classpath:graphiql/main.js");
Map<String, String> config = new HashMap<>();
config.put("LOGO", properties.getGraphiql().getLogo());
config.put("PATH", properties.getPath());
GraphiQlHandler graphiQLHandler = new GraphiQlHandler(htmlResource, jsResource, config);
builder = builder.GET(properties.getGraphiql().getPath() + "/**", graphiQLHandler::handleRequest);
}

if (properties.getSchema().getPrinter().isEnabled()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package org.springframework.graphql.boot;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -117,9 +118,15 @@ public RouterFunction<ServerResponse> graphQlRouterFunction(GraphQlHttpHandler h
handler::handleRequest);

if (properties.getGraphiql().isEnabled()) {
Resource resource = resourceLoader.getResource("classpath:graphiql/index.html");
GraphiQlHandler graphiQLHandler = new GraphiQlHandler(graphQLPath, resource);
builder = builder.GET(properties.getGraphiql().getPath(), graphiQLHandler::handleRequest);
// TODO: should we disable graphiql automatically if optional graphiql module
// is not added to a classpath?
Resource htmlResource = resourceLoader.getResource("classpath:graphiql/index.html");
Resource jsResource = resourceLoader.getResource("classpath:graphiql/main.js");
Map<String, String> config = new HashMap<>();
config.put("LOGO", properties.getGraphiql().getLogo());
config.put("PATH", properties.getPath());
GraphiQlHandler graphiQLHandler = new GraphiQlHandler(htmlResource, jsResource, config);
builder = builder.GET(properties.getGraphiql().getPath() + "/**", graphiQLHandler::handleRequest);
}

if (properties.getSchema().getPrinter().isEnabled()) {
Expand Down
96 changes: 0 additions & 96 deletions graphql-spring-boot-starter/src/main/resources/graphiql/index.html

This file was deleted.

1 change: 1 addition & 0 deletions samples/webflux-websocket/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly project(':spring-graphql-graphiql')
testImplementation project(':spring-graphql-test')
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'io.projectreactor:reactor-test'
Expand Down
1 change: 1 addition & 0 deletions samples/webmvc-http/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ dependencies {
implementation 'com.querydsl:querydsl-core'
implementation 'com.querydsl:querydsl-jpa'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly project(':spring-graphql-graphiql')
runtimeOnly 'com.h2database:h2'
testImplementation project(':spring-graphql-test')
testImplementation 'org.springframework:spring-webflux'
Expand Down
1 change: 1 addition & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pluginManagement {

rootProject.name = 'spring-graphql'
include 'spring-graphql',
'spring-graphql-graphiql',
'spring-graphql-test',
'graphql-spring-boot-starter',
'samples:webmvc-http',
Expand Down
4 changes: 4 additions & 0 deletions spring-graphql-graphiql/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules
build
dist

11 changes: 11 additions & 0 deletions spring-graphql-graphiql/.prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"printWidth": 80,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true,
"trailingComma": "none",
"bracketSpacing": false,
"arrowParens": "avoid",
"parser": "typescript"
}
13 changes: 13 additions & 0 deletions spring-graphql-graphiql/babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module.exports = {
sourceMaps: true,
presets: [
require.resolve('@babel/preset-env'),
require.resolve('@babel/preset-react'),
require.resolve('@babel/preset-typescript'),
],
plugins: [
require.resolve('@babel/plugin-proposal-class-properties'),
// require.resolve('@babel/plugin-transform-runtime')
// [require.resolve('@babel/plugin-transform-runtime'), {"regenerator": true}]
],
};
21 changes: 21 additions & 0 deletions spring-graphql-graphiql/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
plugins {
id 'java-library'
id "com.github.node-gradle.node" version "2.2.0"
}

java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}

node {
version = '10.16.3'
npmVersion = '6.9.0'
download = true
}

jar.dependsOn 'npm_run_mavenbuild'

jar {
from 'dist' into 'graphiql'
}
23 changes: 23 additions & 0 deletions spring-graphql-graphiql/index.html.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<title>Spring GraphQL Explorer</title>
<script src="config.js"></script>
</head>

<body>
<style>
body {
padding: 0;
margin: 0;
min-height: 100vh;
}
#root {
height: 100vh;
}
</style>
<div id="root"></div>
</body>
</html>
Loading

0 comments on commit a6c403e

Please sign in to comment.