Skip to content

Commit

Permalink
Upgrade graphiql (#2346)
Browse files Browse the repository at this point in the history
* Upgrade to graphiql 2.2

Signed-off-by: Thomas Segismont <[email protected]>

* Use graphiql toolkit as data fetcher

Provides both HTTP and GraphQLWS transports

Signed-off-by: Thomas Segismont <[email protected]>

---------

Signed-off-by: Thomas Segismont <[email protected]>
  • Loading branch information
tsegismont authored Jan 30, 2023
1 parent 79faa1b commit 62c0d66
Show file tree
Hide file tree
Showing 45 changed files with 354 additions and 144 deletions.
61 changes: 32 additions & 29 deletions vertx-web-graphql/src/main/asciidoc/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -59,35 +59,6 @@ To enable it, create the {@link io.vertx.ext.web.handler.graphql.GraphQLHandler}
{@link examples.GraphQLExamples#handlerSetupBatching}
----

=== GraphiQL IDE

As you are building your application, testing your GraphQL queries in https://github.com/graphql/graphiql[GraphiQL] can be handy.

To do so, create a route for GraphiQL resources and a {@link io.vertx.ext.web.handler.graphql.GraphiQLHandler} for them:

[source,$lang]
----
{@link examples.GraphQLExamples#handlerSetupGraphiQL}
----

Then browse to http://localhost:8080/graphiql/.

NOTE: The GraphiQL user interface is disabled by default for security reasons.
This is why you must configure the {@link io.vertx.ext.web.handler.graphql.GraphiQLHandlerOptions} to enable it.

TIP: GraphiQL is enabled automatically when Vert.x Web runs in development mode.
To switch the development mode on, use the `VERTXWEB_ENVIRONMENT` environment variable or `vertxweb.environment` system property and set it to `dev`.
In this case, create the {@link io.vertx.ext.web.handler.graphql.GraphiQLHandler} without changing the `enabled` property.

If your application is protected by authentication, you can customize the headers sent by GraphiQL dynamically:

[source,$lang]
----
{@link examples.GraphQLExamples#handlerSetupGraphiQLAuthn}
----

Please refer to the {@link io.vertx.ext.web.handler.graphql.GraphiQLHandlerOptions} documentation for further details.

=== GraphQL over WebSocket

Vert.x Web GraphQL is compatible with the https://github.com/enisdenjo/graphql-ws[GraphQL over Websocket protocol].
Expand Down Expand Up @@ -124,6 +95,38 @@ To support both HTTP and Websockets on the same URI, the {@link io.vertx.ext.web

IMPORTANT: A _subscription_ `DataFetcher` has to return a `org.reactivestreams.Publisher` instance.

=== GraphiQL IDE

As you are building your application, testing your GraphQL queries in https://github.com/graphql/graphiql[GraphiQL] can be handy.

To do so, create a route for GraphiQL resources and a {@link io.vertx.ext.web.handler.graphql.GraphiQLHandler} for them:

[source,$lang]
----
{@link examples.GraphQLExamples#handlerSetupGraphiQL}
----

Then browse to http://localhost:8080/graphiql/.

NOTE: The GraphiQL user interface is disabled by default for security reasons.
This is why you must configure the {@link io.vertx.ext.web.handler.graphql.GraphiQLHandlerOptions} to enable it.

[TIP]
====
GraphiQL is enabled automatically when Vert.x Web runs in development mode.
To switch the development mode on, use the `VERTXWEB_ENVIRONMENT` environment variable or `vertxweb.environment` system property and set it to `dev`.
In this case, create the {@link io.vertx.ext.web.handler.graphql.GraphiQLHandler} without changing the `enabled` property.
====

If your application is protected by authentication, you can customize the headers sent by GraphiQL dynamically:

[source,$lang]
----
{@link examples.GraphQLExamples#handlerSetupGraphiQLAuthn}
----

Please refer to the {@link io.vertx.ext.web.handler.graphql.GraphiQLHandlerOptions} documentation for further details.

== Fetching data

The GraphQL-Java API is very well suited for the asynchronous world: the asynchronous execution strategy is the default for queries (serial asynchronous for mutations).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,18 @@ public static void fromJson(Iterable<java.util.Map.Entry<String, Object>> json,
obj.setGraphQLUri((String)member.getValue());
}
break;
case "graphQLWSEnabled":
if (member.getValue() instanceof Boolean) {
obj.setGraphQLWSEnabled((Boolean)member.getValue());
}
break;
case "graphQLWSUri":
break;
case "graphWSQLUri":
if (member.getValue() instanceof String) {
obj.setGraphWSQLUri((String)member.getValue());
}
break;
case "headers":
if (member.getValue() instanceof JsonObject) {
java.util.Map<String, java.lang.String> map = new java.util.LinkedHashMap<>();
Expand All @@ -40,6 +52,11 @@ public static void fromJson(Iterable<java.util.Map.Entry<String, Object>> json,
obj.setHeaders(map);
}
break;
case "httpEnabled":
if (member.getValue() instanceof Boolean) {
obj.setHttpEnabled((Boolean)member.getValue());
}
break;
case "query":
if (member.getValue() instanceof String) {
obj.setQuery((String)member.getValue());
Expand All @@ -50,6 +67,11 @@ public static void fromJson(Iterable<java.util.Map.Entry<String, Object>> json,
obj.setVariables(((JsonObject)member.getValue()).copy());
}
break;
case "wsConnectionParams":
if (member.getValue() instanceof JsonObject) {
obj.setWsConnectionParams(((JsonObject)member.getValue()).copy());
}
break;
}
}
}
Expand All @@ -63,16 +85,24 @@ public static void toJson(GraphiQLHandlerOptions obj, java.util.Map<String, Obje
if (obj.getGraphQLUri() != null) {
json.put("graphQLUri", obj.getGraphQLUri());
}
json.put("graphQLWSEnabled", obj.isGraphQLWSEnabled());
if (obj.getGraphQLWSUri() != null) {
json.put("graphQLWSUri", obj.getGraphQLWSUri());
}
if (obj.getHeaders() != null) {
JsonObject map = new JsonObject();
obj.getHeaders().forEach((key, value) -> map.put(key, value));
json.put("headers", map);
}
json.put("httpEnabled", obj.isHttpEnabled());
if (obj.getQuery() != null) {
json.put("query", obj.getQuery());
}
if (obj.getVariables() != null) {
json.put("variables", obj.getVariables());
}
if (obj.getWsConnectionParams() != null) {
json.put("wsConnectionParams", obj.getWsConnectionParams());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,31 @@ public class GraphiQLHandlerOptions {
*/
public static final boolean DEFAULT_ENABLED = WebEnvironment.development();

/**
* Whether HTTP transport should be enabled by default = true.
*/
public static final boolean DEFAULT_HTTP_ENABLED = true;

/**
* Default URI for HTTP and GraphQLWS endpoints = /graphql.
*/
public static final String DEFAULT_GRAPHQL_URI = "/graphql";

/**
* Whether GraphQLWS transport should be enabled by default = true.
*/
public static final boolean DEFAULT_GRAPHQL_WS_ENABLED = true;

private boolean enabled = DEFAULT_ENABLED;

private String graphQLUri;
private boolean httpEnabled = DEFAULT_HTTP_ENABLED;
private String graphQLUri = DEFAULT_GRAPHQL_URI;

private boolean graphQLWSEnabled = DEFAULT_GRAPHQL_WS_ENABLED;
private String graphQLWSUri = DEFAULT_GRAPHQL_URI;

private Map<String, String> headers;
private JsonObject wsConnectionParams;

private String query;

Expand All @@ -59,8 +79,12 @@ public GraphiQLHandlerOptions() {
*/
public GraphiQLHandlerOptions(GraphiQLHandlerOptions other) {
enabled = other.enabled;
httpEnabled = other.httpEnabled;
graphQLUri = other.graphQLUri;
graphQLWSEnabled = other.graphQLWSEnabled;
graphQLWSUri = other.graphQLWSUri;
headers = other.headers == null ? null : new HashMap<>(other.headers);
wsConnectionParams = other.wsConnectionParams == null ? null : other.wsConnectionParams.copy();
query = other.query;
variables = other.variables == null ? null : other.variables.copy();
}
Expand All @@ -85,7 +109,7 @@ public JsonObject toJson() {
}

/**
* @return true if the GraphiQL development tool should be enabled, false otherwise
* @return {@code true} if the GraphiQL development tool should be enabled, {@code false} otherwise
*/
public boolean isEnabled() {
return enabled;
Expand All @@ -94,15 +118,32 @@ public boolean isEnabled() {
/**
* Whether the GraphiQL development tool should be enabled. Defaults to {@code false}.
*
* @param enabled true to enable the GraphiQL development tool, false otherwise
*
* @param enabled {@code true} to enable the GraphiQL development tool, {@code false} otherwise
* @return a reference to this, so the API can be used fluently
*/
public GraphiQLHandlerOptions setEnabled(boolean enabled) {
this.enabled = enabled;
return this;
}

/**
* @return {@code true} if the HTTP transport should be enabled, {@code true} otherwise
*/
public boolean isHttpEnabled() {
return httpEnabled;
}

/**
* Whether the HTTP transport should be enabled. Defaults to {@code true}.
*
* @param httpEnabled {@code true} to enable the HTTP transport, {@code false} otherwise
* @return a reference to this, so the API can be used fluently
*/
public GraphiQLHandlerOptions setHttpEnabled(boolean httpEnabled) {
this.httpEnabled = httpEnabled;
return this;
}

/**
* @return the GraphQL endpoint URI
*/
Expand All @@ -111,17 +152,52 @@ public String getGraphQLUri() {
}

/**
* Set the GraphQL endpoint URI. Defaults to the path used to get the GraphiQL user interface.
*
* @param graphQLUri the GraphQL endpoint URI
* Set the GraphQL HTTP endpoint URI. Defaults to {@link #DEFAULT_GRAPHQL_URI}.
*
* @param graphQLUri the GraphQL HTTP endpoint URI
* @return a reference to this, so the API can be used fluently
*/
public GraphiQLHandlerOptions setGraphQLUri(String graphQLUri) {
this.graphQLUri = graphQLUri;
return this;
}

/**
* @return {@code true} if the GraphQLWS transport should be enabled, {@code true} otherwise
*/
public boolean isGraphQLWSEnabled() {
return graphQLWSEnabled;
}

/**
* Whether the GraphQLWS transport should be enabled. Defaults to {@code true}.
*
* @param graphQLWSEnabled {@code true} to enable the GraphQLWS transport, {@code false} otherwise
* @return a reference to this, so the API can be used fluently
*/
public GraphiQLHandlerOptions setGraphQLWSEnabled(boolean graphQLWSEnabled) {
this.graphQLWSEnabled = graphQLWSEnabled;
return this;
}

/**
* @return the GraphQLWS endpoint URI
*/
public String getGraphQLWSUri() {
return graphQLWSUri;
}

/**
* Set the GraphQLWS endpoint URI. Defaults to {@link #DEFAULT_GRAPHQL_URI}.
*
* @param graphQLWSUri the GraphQLWS endpoint URI
* @return a reference to this, so the API can be used fluently
*/
public GraphiQLHandlerOptions setGraphWSQLUri(String graphQLWSUri) {
this.graphQLWSUri = graphQLWSUri;
return this;
}

/**
* @return the fixed set of HTTP headers to add to GraphiQL requests
*/
Expand All @@ -133,14 +209,31 @@ public Map<String, String> getHeaders() {
* A fixed set of HTTP headers to add to GraphiQL requests. Defaults to {@code null}.
*
* @param headers the set of HTTP headers to add to GraphiQL requests
*
* @return a reference to this, so the API can be used fluently
*/
public GraphiQLHandlerOptions setHeaders(Map<String, String> headers) {
this.headers = headers;
return this;
}

/**
* @return the initial GraphQLWS connection params
*/
public JsonObject getWsConnectionParams() {
return wsConnectionParams;
}

/**
* Initial GraphQLWS connection params. Defaults to {@code null}.
*
* @param wsConnectionParams the initial GraphQLWS connection params
* @return a reference to this, so the API can be used fluently
*/
public GraphiQLHandlerOptions setWsConnectionParams(JsonObject wsConnectionParams) {
this.wsConnectionParams = wsConnectionParams;
return this;
}

/**
* @return the query to set as initial value in the GraphiQL user interface
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,8 @@
import java.util.Objects;
import java.util.function.Function;

import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.concurrent.TimeUnit.DAYS;
import static java.util.concurrent.TimeUnit.SECONDS;
import static java.nio.charset.StandardCharsets.*;
import static java.util.concurrent.TimeUnit.*;

/**
* @author Thomas Segismont
Expand Down Expand Up @@ -89,9 +88,17 @@ public void handle(RoutingContext rc) {

private String replacement(RoutingContext rc) {
JsonObject json = new JsonObject();
json.put("httpEnabled", options.isHttpEnabled());
if (options.getGraphQLUri() != null) {
json.put("graphQLUri", options.getGraphQLUri());
}
json.put("graphQLWSEnabled", options.isGraphQLWSEnabled());
if (options.getGraphQLWSUri() != null) {
json.put("graphQLWSUri", options.getGraphQLWSUri());
}
if (options.getWsConnectionParams() != null) {
json.put("wsConnectionParams", options.getWsConnectionParams());
}
MultiMap headers = MultiMap.caseInsensitiveMultiMap();
Map<String, String> fixedHeaders = options.getHeaders();
if (fixedHeaders != null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><title>GraphiQL</title><script>window.VERTX_GRAPHIQL_CONFIG=__VERTX_GRAPHIQL_CONFIG__</script><link href="./static/css/2.7b8c1680.chunk.css" rel="stylesheet"><link href="./static/css/main.8faf0fb8.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(l){function e(e){for(var r,t,n=e[0],o=e[1],u=e[2],f=0,i=[];f<n.length;f++)t=n[f],p[t]&&i.push(p[t][0]),p[t]=0;for(r in o)Object.prototype.hasOwnProperty.call(o,r)&&(l[r]=o[r]);for(s&&s(e);i.length;)i.shift()();return c.push.apply(c,u||[]),a()}function a(){for(var e,r=0;r<c.length;r++){for(var t=c[r],n=!0,o=1;o<t.length;o++){var u=t[o];0!==p[u]&&(n=!1)}n&&(c.splice(r--,1),e=f(f.s=t[0]))}return e}var t={},p={1:0},c=[];function f(e){if(t[e])return t[e].exports;var r=t[e]={i:e,l:!1,exports:{}};return l[e].call(r.exports,r,r.exports,f),r.l=!0,r.exports}f.m=l,f.c=t,f.d=function(e,r,t){f.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},f.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.t=function(r,e){if(1&e&&(r=f(r)),8&e)return r;if(4&e&&"object"==typeof r&&r&&r.__esModule)return r;var t=Object.create(null);if(f.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:r}),2&e&&"string"!=typeof r)for(var n in r)f.d(t,n,function(e){return r[e]}.bind(null,n));return t},f.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return f.d(r,"a",r),r},f.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},f.p="./";var r=window.webpackJsonp=window.webpackJsonp||[],n=r.push.bind(r);r.push=e,r=r.slice();for(var o=0;o<r.length;o++)e(r[o]);var s=n;a()}([])</script><script src="./static/js/2.9f085c6c.chunk.js"></script><script src="./static/js/main.655dbc04.chunk.js"></script></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"/><meta name="theme-color" content="#000000"/><title>GraphiQL</title><script>window.VERTX_GRAPHIQL_CONFIG=__VERTX_GRAPHIQL_CONFIG__</script><script defer="defer" src="./static/js/main.be49c935.js"></script><link href="./static/css/main.87812244.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>

This file was deleted.

Large diffs are not rendered by default.

This file was deleted.

Loading

0 comments on commit 62c0d66

Please sign in to comment.