diff --git a/README.md b/README.md
index 4e0b01d..ef3f40c 100644
--- a/README.md
+++ b/README.md
@@ -20,6 +20,7 @@ pip install "graphene-django>=2.0"
```python
INSTALLED_APPS = (
# ...
+ 'django.contrib.staticfiles', # Required for GraphiQL
'graphene_django',
)
diff --git a/graphene_django/static/graphene_django/graphiql.js b/graphene_django/static/graphene_django/graphiql.js
new file mode 100644
index 0000000..2be7e3c
--- /dev/null
+++ b/graphene_django/static/graphene_django/graphiql.js
@@ -0,0 +1,99 @@
+(function() {
+
+ // Parse the cookie value for a CSRF token
+ var csrftoken;
+ var cookies = ('; ' + document.cookie).split('; csrftoken=');
+ if (cookies.length == 2)
+ csrftoken = cookies.pop().split(';').shift();
+
+ // Collect the URL parameters
+ var parameters = {};
+ window.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('&');
+ }
+ // Derive a fetch URL from the current URL, sans the GraphQL parameters.
+ var graphqlParamNames = {
+ query: true,
+ variables: true,
+ operationName: true
+ };
+ var otherParams = {};
+ for (var k in parameters) {
+ if (parameters.hasOwnProperty(k) && graphqlParamNames[k] !== true) {
+ otherParams[k] = parameters[k];
+ }
+ }
+
+ var fetchURL = locationQuery(otherParams);
+
+ // Defines a GraphQL fetcher using the fetch API.
+ function graphQLFetcher(graphQLParams) {
+ var headers = {
+ 'Accept': 'application/json',
+ 'Content-Type': 'application/json'
+ };
+ if (csrftoken) {
+ headers['X-CSRFToken'] = csrftoken;
+ }
+ return fetch(fetchURL, {
+ 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;
+ }
+ });
+ }
+ // When the query and variables string is edited, update the URL bar so
+ // that it can be easily shared.
+ function onEditQuery(newQuery) {
+ parameters.query = newQuery;
+ updateURL();
+ }
+ function onEditVariables(newVariables) {
+ parameters.variables = newVariables;
+ updateURL();
+ }
+ function onEditOperationName(newOperationName) {
+ parameters.operationName = newOperationName;
+ updateURL();
+ }
+ function updateURL() {
+ history.replaceState(null, null, locationQuery(parameters));
+ }
+ var options = {
+ fetcher: graphQLFetcher,
+ onEditQuery: onEditQuery,
+ onEditVariables: onEditVariables,
+ onEditOperationName: onEditOperationName,
+ query: parameters.query,
+ }
+ if (parameters.variables) {
+ options.variables = parameters.variables;
+ }
+ if (parameters.operation_name) {
+ options.operationName = parameters.operation_name;
+ }
+ // Render