diff --git a/graphene_django/static/graphene_django/graphiql.js b/graphene_django/static/graphene_django/graphiql.js index 1bc3255d4..17836efd9 100644 --- a/graphene_django/static/graphene_django/graphiql.js +++ b/graphene_django/static/graphene_django/graphiql.js @@ -1,43 +1,55 @@ (function ( document, + GRAPHENE_SETTINGS, GraphiQL, React, ReactDOM, SubscriptionsTransportWs, + fetch, history, location, ) { // Parse the cookie value for a CSRF token var csrftoken; - var cookies = ('; ' + document.cookie).split('; csrftoken='); + var cookies = ("; " + document.cookie).split("; csrftoken="); if (cookies.length == 2) { - csrftoken = cookies.pop().split(';').shift(); + csrftoken = cookies.pop().split(";").shift(); } else { csrftoken = document.querySelector("[name=csrfmiddlewaretoken]").value; } // Collect the URL parameters var parameters = {}; - location.hash.substr(1).split('&').forEach(function (entry) { - var eq = entry.indexOf('='); - if (eq >= 0) { - parameters[decodeURIComponent(entry.slice(0, eq))] = - decodeURIComponent(entry.slice(eq + 1)); - } - }); + location.hash + .substr(1) + .split("&") + .forEach(function (entry) { + var eq = entry.indexOf("="); + if (eq >= 0) { + parameters[decodeURIComponent(entry.slice(0, eq))] = decodeURIComponent( + entry.slice(eq + 1), + ); + } + }); // Produce a Location fragment string from a parameter object. function locationQuery(params) { - return '#' + Object.keys(params).map(function (key) { - return encodeURIComponent(key) + '=' + - encodeURIComponent(params[key]); - }).join('&'); + return ( + "#" + + Object.keys(params) + .map(function (key) { + return ( + encodeURIComponent(key) + "=" + encodeURIComponent(params[key]) + ); + }) + .join("&") + ); } // Derive a fetch URL from the current URL, sans the GraphQL parameters. var graphqlParamNames = { query: true, variables: true, - operationName: true + operationName: true, }; var otherParams = {}; for (var k in parameters) { @@ -51,26 +63,28 @@ // Defines a GraphQL fetcher using the fetch API. function httpClient(graphQLParams) { var headers = { - 'Accept': 'application/json', - 'Content-Type': 'application/json' + Accept: "application/json", + "Content-Type": "application/json", }; if (csrftoken) { - headers['X-CSRFToken'] = csrftoken; + headers["X-CSRFToken"] = csrftoken; } return fetch(fetchURL, { - method: 'post', + method: "post", headers: headers, body: JSON.stringify(graphQLParams), - credentials: 'include', - }).then(function (response) { - return response.text(); - }).then(function (responseBody) { - try { - return JSON.parse(responseBody); - } catch (error) { - return responseBody; - } - }); + credentials: "include", + }) + .then(function (response) { + return response.text(); + }) + .then(function (responseBody) { + try { + return JSON.parse(responseBody); + } catch (error) { + return responseBody; + } + }); } // Derive the subscription URL. If the SUBSCRIPTION_URL setting is specified, uses that value. Otherwise @@ -157,7 +171,7 @@ onEditVariables: onEditVariables, onEditOperationName: onEditOperationName, query: parameters.query, - } + }; if (parameters.variables) { options.variables = parameters.variables; } @@ -167,15 +181,17 @@ // Render into the body. ReactDOM.render( React.createElement(GraphiQL, options), - document.getElementById("editor") + document.getElementById("editor"), ); })( document, + window.GRAPHENE_SETTINGS, window.GraphiQL, window.React, window.ReactDOM, window.SubscriptionsTransportWs, + window.fetch, window.history, window.location, ); diff --git a/graphene_django/templates/graphene/graphiql.html b/graphene_django/templates/graphene/graphiql.html index 20ac1d019..abc4b5262 100644 --- a/graphene_django/templates/graphene/graphiql.html +++ b/graphene_django/templates/graphene/graphiql.html @@ -17,19 +17,24 @@ width: 100%; } - - diff --git a/graphene_django/views.py b/graphene_django/views.py index 22b486443..59084e8eb 100644 --- a/graphene_django/views.py +++ b/graphene_django/views.py @@ -52,10 +52,27 @@ def instantiate_middleware(middlewares): class GraphQLView(View): - graphiql_version = "1.0.3" graphiql_template = "graphene/graphiql.html" + + # Polyfill for window.fetch. + whatwg_fetch_version = "3.2.0" + whatwg_fetch_sri = "sha256-l6HCB9TT2v89oWbDdo2Z3j+PSVypKNLA/nqfzSbM8mo=" + + # React and ReactDOM. react_version = "16.13.1" - subscriptions_transport_ws_version = "0.9.16" + react_sri = "sha256-yUhvEmYVhZ/GGshIQKArLvySDSh6cdmdcIx0spR3UP4=" + react_dom_sri = "sha256-vFt3l+illeNlwThbDUdoPTqF81M8WNSZZZt3HEjsbSU=" + + # The GraphiQL React app. + graphiql_version = "1.0.3" + graphiql_sri = "sha256-VR4buIDY9ZXSyCNFHFNik6uSe0MhigCzgN4u7moCOTk=" + graphiql_css_sri = "sha256-LwqxjyZgqXDYbpxQJ5zLQeNcf7WVNSJ+r8yp2rnWE/E=" + + # The websocket transport library for subscriptions. + subscriptions_transport_ws_version = "0.9.17" + subscriptions_transport_ws_sri = ( + "sha256-kCDzver8iRaIQ/SVlfrIwxaBQ/avXf9GQFJRLlErBnk=" + ) schema = None graphiql = False @@ -101,7 +118,7 @@ def __init__( self.batch = self.batch or batch self.backend = backend if subscription_path is None: - subscription_path = graphene_settings.SUBSCRIPTION_PATH + self.subscription_path = graphene_settings.SUBSCRIPTION_PATH assert isinstance( self.schema, GraphQLSchema @@ -137,9 +154,18 @@ def dispatch(self, request, *args, **kwargs): if show_graphiql: return self.render_graphiql( request, - graphiql_version=self.graphiql_version, + # Dependency parameters. + whatwg_fetch_version=self.whatwg_fetch_version, + whatwg_fetch_sri=self.whatwg_fetch_sri, react_version=self.react_version, + react_sri=self.react_sri, + react_dom_sri=self.react_dom_sri, + graphiql_version=self.graphiql_version, + graphiql_sri=self.graphiql_sri, + graphiql_css_sri=self.graphiql_css_sri, subscriptions_transport_ws_version=self.subscriptions_transport_ws_version, + subscriptions_transport_ws_sri=self.subscriptions_transport_ws_sri, + # The SUBSCRIPTION_PATH setting. subscription_path=self.subscription_path, )