diff --git a/graphene_django/static/graphene_django/graphiql.js b/graphene_django/static/graphene_django/graphiql.js index f6be32c..106b470 100644 --- a/graphene_django/static/graphene_django/graphiql.js +++ b/graphene_django/static/graphene_django/graphiql.js @@ -5,7 +5,7 @@ GraphiQL, React, ReactDOM, - SubscriptionsTransportWs, + graphqlWs, fetch, history, location, @@ -52,8 +52,24 @@ var fetchURL = locationQuery(otherParams); - // Defines a GraphQL fetcher using the fetch API. - function httpClient(graphQLParams, opts) { + // Derive the subscription URL. If the SUBSCRIPTION_URL setting is specified, uses that value. Otherwise + // assumes the current window location with an appropriate websocket protocol. + var subscribeURL = + location.origin.replace(/^http/, "ws") + + (GRAPHENE_SETTINGS.subscriptionPath || location.pathname); + + function trueLambda() { return true; }; + + var fetcher = GraphiQL.createFetcher({ + url: fetchURL, + wsClient: graphqlWs.createClient({ + url: subscribeURL, + shouldRetry: trueLambda, + lazy: true, + }) + }) + + function graphQLFetcher(graphQLParams, opts) { if (typeof opts === 'undefined') { opts = {}; } @@ -73,86 +89,9 @@ 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; - } - }); - } + opts.headers = headers - // Derive the subscription URL. If the SUBSCRIPTION_URL setting is specified, uses that value. Otherwise - // assumes the current window location with an appropriate websocket protocol. - var subscribeURL = - location.origin.replace(/^http/, "ws") + - (GRAPHENE_SETTINGS.subscriptionPath || location.pathname); - - // Create a subscription client. - var subscriptionClient = new SubscriptionsTransportWs.SubscriptionClient( - subscribeURL, - { - // Reconnect after any interruptions. - reconnect: true, - // Delay socket initialization until the first subscription is started. - lazy: true, - }, - ); - - // Keep a reference to the currently-active subscription, if available. - var activeSubscription = null; - - // Define a GraphQL fetcher that can intelligently route queries based on the operation type. - function graphQLFetcher(graphQLParams, opts) { - var operationType = getOperationType(graphQLParams); - - // If we're about to execute a new operation, and we have an active subscription, - // unsubscribe before continuing. - if (activeSubscription) { - activeSubscription.unsubscribe(); - activeSubscription = null; - } - - if (operationType === "subscription") { - return { - subscribe: function (observer) { - activeSubscription = subscriptionClient; - return subscriptionClient.request(graphQLParams, opts).subscribe(observer); - }, - }; - } else { - return httpClient(graphQLParams, opts); - } - } - - // Determine the type of operation being executed for a given set of GraphQL parameters. - function getOperationType(graphQLParams) { - // Run a regex against the query to determine the operation type (query, mutation, subscription). - var operationRegex = new RegExp( - // Look for lines that start with an operation keyword, ignoring whitespace. - "^\\s*(query|mutation|subscription)\\s*" + - // The operation keyword should be followed by whitespace and the operationName in the GraphQL parameters (if available). - (graphQLParams.operationName ? ("\\s+" + graphQLParams.operationName) : "") + - // The line should eventually encounter an opening curly brace. - "[^\\{]*\\{", - // Enable multiline matching. - "m", - ); - var match = operationRegex.exec(graphQLParams.query); - if (!match) { - return "query"; - } - - return match[1]; + return fetcher(graphQLParams, opts) } // When the query and variables string is edited, update the URL bar so @@ -177,7 +116,7 @@ onEditQuery: onEditQuery, onEditVariables: onEditVariables, onEditOperationName: onEditOperationName, - headerEditorEnabled: GRAPHENE_SETTINGS.graphiqlHeaderEditorEnabled, + isHeadersEditorEnabled: GRAPHENE_SETTINGS.graphiqlHeaderEditorEnabled, shouldPersistHeaders: GRAPHENE_SETTINGS.graphiqlShouldPersistHeaders, query: parameters.query, }; @@ -199,7 +138,7 @@ window.GraphiQL, window.React, window.ReactDOM, - window.SubscriptionsTransportWs, + window.graphqlWs, window.fetch, window.history, window.location, diff --git a/graphene_django/templates/graphene/graphiql.html b/graphene_django/templates/graphene/graphiql.html index 3685692..8fb00c4 100644 --- a/graphene_django/templates/graphene/graphiql.html +++ b/graphene_django/templates/graphene/graphiql.html @@ -33,7 +33,7 @@ add "&raw" to the end of the URL within a browser. - diff --git a/graphene_django/views.py b/graphene_django/views.py index 4d68b13..b29aeed 100644 --- a/graphene_django/views.py +++ b/graphene_django/views.py @@ -66,14 +66,14 @@ class GraphQLView(View): react_dom_sri = "sha256-nbMykgB6tsOFJ7OdVmPpdqMFVk4ZsqWocT6issAPUF0=" # The GraphiQL React app. - graphiql_version = "1.4.7" # "1.0.3" - graphiql_sri = "sha256-cpZ8w9D/i6XdEbY/Eu7yAXeYzReVw0mxYd7OU3gUcsc=" # "sha256-VR4buIDY9ZXSyCNFHFNik6uSe0MhigCzgN4u7moCOTk=" - graphiql_css_sri = "sha256-HADQowUuFum02+Ckkv5Yu5ygRoLllHZqg0TFZXY7NHI=" # "sha256-LwqxjyZgqXDYbpxQJ5zLQeNcf7WVNSJ+r8yp2rnWE/E=" + graphiql_version = "2.4.1" # "1.0.3" + graphiql_sri = "sha256-s+f7CFAPSUIygFnRC2nfoiEKd3liCUy+snSdYFAoLUc=" # "sha256-VR4buIDY9ZXSyCNFHFNik6uSe0MhigCzgN4u7moCOTk=" + graphiql_css_sri = "sha256-88yn8FJMyGboGs4Bj+Pbb3kWOWXo7jmb+XCRHE+282k=" # "sha256-LwqxjyZgqXDYbpxQJ5zLQeNcf7WVNSJ+r8yp2rnWE/E=" # The websocket transport library for subscriptions. - subscriptions_transport_ws_version = "0.9.18" + subscriptions_transport_ws_version = "5.12.1" subscriptions_transport_ws_sri = ( - "sha256-i0hAXd4PdJ/cHX3/8tIy/Q/qKiWr5WSTxMFuL9tACkw=" + "sha256-EZhvg6ANJrBsgLvLAa0uuHNLepLJVCFYS+xlb5U/bqw=" ) schema = None