diff --git a/graphiql.go b/graphiql.go
index b024086..77c03ea 100644
--- a/graphiql.go
+++ b/graphiql.go
@@ -4,21 +4,27 @@ import (
"encoding/json"
"html/template"
"net/http"
+ "strings"
"github.com/graphql-go/graphql"
)
-// graphiqlData is the page data structure of the rendered GraphiQL page
+// data is the page data structure of the rendered GraphiQL page
type graphiqlData struct {
- GraphiqlVersion string
- QueryString string
- VariablesString string
- OperationName string
- ResultString string
+ GraphiqlVersion string
+ SubscriptionTransportVersion string
+ QueryString string
+ ResultString string
+ VariablesString string
+ OperationName string
+ Endpoint template.URL
+ SubscriptionEndpoint template.URL
+ UsingHTTP bool
+ UsingWS bool
}
// renderGraphiQL renders the GraphiQL GUI
-func renderGraphiQL(w http.ResponseWriter, params graphql.Params) {
+func renderGraphiQL(w http.ResponseWriter, params graphql.Params, handler Handler) {
t := template.New("GraphiQL")
t, err := t.Parse(graphiqlTemplate)
if err != nil {
@@ -50,12 +56,29 @@ func renderGraphiQL(w http.ResponseWriter, params graphql.Params) {
resString = string(result)
}
+ isEndpointUsingWS := strings.HasPrefix(handler.Endpoint, "ws://")
+ UsingHTTP := !isEndpointUsingWS
+ UsingWS := isEndpointUsingWS || handler.SubscriptionsEndpoint != ""
+ SubscriptionEndpoint := ""
+ if UsingWS {
+ if isEndpointUsingWS {
+ SubscriptionEndpoint = handler.Endpoint
+ } else {
+ SubscriptionEndpoint = handler.SubscriptionsEndpoint
+ }
+ }
+
d := graphiqlData{
- GraphiqlVersion: graphiqlVersion,
- QueryString: params.RequestString,
- ResultString: resString,
- VariablesString: varsString,
- OperationName: params.OperationName,
+ GraphiqlVersion: graphiqlVersion,
+ SubscriptionTransportVersion: subscriptionTransportVersion,
+ QueryString: params.RequestString,
+ ResultString: resString,
+ VariablesString: varsString,
+ OperationName: params.OperationName,
+ Endpoint: template.URL(handler.Endpoint),
+ SubscriptionEndpoint: template.URL(SubscriptionEndpoint),
+ UsingHTTP: UsingHTTP,
+ UsingWS: UsingWS,
}
err = t.ExecuteTemplate(w, "index", d)
if err != nil {
@@ -68,6 +91,9 @@ func renderGraphiQL(w http.ResponseWriter, params graphql.Params) {
// graphiqlVersion is the current version of GraphiQL
const graphiqlVersion = "0.11.11"
+// subscriptionTransportVersion is the current version of the subscription transport of GraphiQL
+const subscriptionTransportVersion = "0.8.2"
+
// tmpl is the page template to render GraphiQL
const graphiqlTemplate = `
{{ define "index" }}
@@ -103,6 +129,17 @@ add "&raw" to the end of the URL within a browser.
+
+ {{ if .UsingHTTP }}
+
+ {{ end }}
+ {{ if .UsingWS }}
+
+ {{ end }}
+ {{ if and .UsingWS .UsingHTTP }}
+
+ {{ end }}
+
Loading...
@@ -118,10 +155,8 @@ add "&raw" to the end of the URL within a browser.
});
// Produce a Location query string from a parameter object.
- function locationQuery(params) {
- return '?' + Object.keys(params).filter(function (key) {
- return Boolean(params[key]);
- }).map(function (key) {
+ function locationQuery(params, location) {
+ return (location ? location: '') + '?' + Object.keys(params).map(function (key) {
return encodeURIComponent(key) + '=' +
encodeURIComponent(params[key]);
}).join('&');
@@ -140,28 +175,49 @@ add "&raw" to the end of the URL within a browser.
otherParams[k] = parameters[k];
}
}
- var fetchURL = locationQuery(otherParams);
-
- // Defines a GraphQL fetcher using the fetch API.
- function graphQLFetcher(graphQLParams) {
- return fetch(fetchURL, {
- method: 'post',
- headers: {
- 'Accept': 'application/json',
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify(graphQLParams),
- credentials: 'include',
- }).then(function (response) {
- return response.text();
- }).then(function (responseBody) {
- try {
- return JSON.parse(responseBody);
- } catch (error) {
- return responseBody;
- }
+
+ {{ if .UsingWS }}
+ var subscriptionsClient = new window.SubscriptionsTransportWs.SubscriptionClient({{ .SubscriptionEndpoint }}, {
+ reconnect: true
});
- }
+ var graphQLWSFetcher = subscriptionsClient.request.bind(subscriptionsClient);
+ {{ end }}
+
+ {{ if .UsingHTTP }}
+ var fetchURL = locationQuery(otherParams, {{ .Endpoint }});
+
+ // Defines a GraphQL fetcher using the fetch API.
+ function graphQLHttpFetcher(graphQLParams) {
+ return fetch(fetchURL, {
+ method: 'post',
+ headers: {
+ 'Accept': 'application/json',
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify(graphQLParams),
+ credentials: 'include',
+ }).then(function (response) {
+ return response.text();
+ }).then(function (responseBody) {
+ try {
+ return JSON.parse(responseBody);
+ } catch (error) {
+ return responseBody;
+ }
+ });
+ }
+ {{ end }}
+
+ {{ if and .UsingWS .UsingHTTP }}
+ var fetcher = window.GraphiQLSubscriptionsFetcher.graphQLFetcher(subscriptionsClient, graphQLHttpFetcher);
+ {{ else }}
+ {{ if .UsingWS }}
+ var fetcher = graphQLWSFetcher;
+ {{ end }}
+ {{ if .UsingHTTP }}
+ var fetcher = graphQLHttpFetcher;
+ {{ end }}
+ {{ end }}
// When the query and variables string is edited, update the URL bar so
// that it can be easily shared.
@@ -187,7 +243,7 @@ add "&raw" to the end of the URL within a browser.
// Render into the body.
ReactDOM.render(
React.createElement(GraphiQL, {
- fetcher: graphQLFetcher,
+ fetcher: fetcher,
onEditQuery: onEditQuery,
onEditVariables: onEditVariables,
onEditOperationName: onEditOperationName,
diff --git a/handler.go b/handler.go
index b9a647c..c5b6aa7 100644
--- a/handler.go
+++ b/handler.go
@@ -23,13 +23,15 @@ const (
type ResultCallbackFn func(ctx context.Context, params *graphql.Params, result *graphql.Result, responseBody []byte)
type Handler struct {
- Schema *graphql.Schema
- pretty bool
- graphiql bool
- playground bool
- rootObjectFn RootObjectFn
- resultCallbackFn ResultCallbackFn
- formatErrorFn func(err error) gqlerrors.FormattedError
+ Schema *graphql.Schema
+ pretty bool
+ graphiql bool
+ Endpoint string
+ SubscriptionsEndpoint string
+ playground bool
+ rootObjectFn RootObjectFn
+ resultCallbackFn ResultCallbackFn
+ formatErrorFn func(err error) gqlerrors.FormattedError
}
type RequestOptions struct {
@@ -153,7 +155,7 @@ func (h *Handler) ContextHandler(ctx context.Context, w http.ResponseWriter, r *
acceptHeader := r.Header.Get("Accept")
_, raw := r.URL.Query()["raw"]
if !raw && !strings.Contains(acceptHeader, "application/json") && strings.Contains(acceptHeader, "text/html") {
- renderGraphiQL(w, params)
+ renderGraphiQL(w, params, *h)
return
}
}
@@ -197,21 +199,25 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
type RootObjectFn func(ctx context.Context, r *http.Request) map[string]interface{}
type Config struct {
- Schema *graphql.Schema
- Pretty bool
- GraphiQL bool
- Playground bool
- RootObjectFn RootObjectFn
- ResultCallbackFn ResultCallbackFn
- FormatErrorFn func(err error) gqlerrors.FormattedError
+ Schema *graphql.Schema
+ Pretty bool
+ GraphiQL bool
+ Endpoint string
+ SubscriptionsEndpoint string
+ Playground bool
+ RootObjectFn RootObjectFn
+ ResultCallbackFn ResultCallbackFn
+ FormatErrorFn func(err error) gqlerrors.FormattedError
}
func NewConfig() *Config {
return &Config{
- Schema: nil,
- Pretty: true,
- GraphiQL: true,
- Playground: false,
+ Schema: nil,
+ Pretty: true,
+ GraphiQL: true,
+ Endpoint: "",
+ SubscriptionsEndpoint: "",
+ Playground: false,
}
}
@@ -225,12 +231,14 @@ func New(p *Config) *Handler {
}
return &Handler{
- Schema: p.Schema,
- pretty: p.Pretty,
- graphiql: p.GraphiQL,
- playground: p.Playground,
- rootObjectFn: p.RootObjectFn,
- resultCallbackFn: p.ResultCallbackFn,
- formatErrorFn: p.FormatErrorFn,
+ Schema: p.Schema,
+ pretty: p.Pretty,
+ graphiql: p.GraphiQL,
+ Endpoint: p.Endpoint,
+ SubscriptionsEndpoint: p.SubscriptionsEndpoint,
+ playground: p.Playground,
+ rootObjectFn: p.RootObjectFn,
+ resultCallbackFn: p.ResultCallbackFn,
+ formatErrorFn: p.FormatErrorFn,
}
}