if (!Object.assign) { throw “StreamingGraphQLClient requires Object.assign” }
var StreamingGraphQLClient = {
// Send a GraphQL query to the server, // then receive patches from `\n\n`-delimited chunks. // For each patch, call `onResponse` with the updated response (data and errors) // @example Send a GraphQL query and handle the response // var queryString = "{ items @stream { name } }" // var queryVariables = {} // // // Response handler checks for errors // var handleResponse = function(response) { // if (response.errors) { // alert("Uh oh, something went wrong!\n\n" + JSON.stringify(response.errors)) // } else { // _this.setState({items: response.items}) // } // } // // StreamingGraphQL.fetch("/graphql", queryString, queryVariables, handleResponse) // fetch: function(endpointPath, queryString, variables, onResponse) { var xhr = new XMLHttpRequest() xhr.open("POST", endpointPath) xhr.setRequestHeader('Content-Type', 'application/json') var csrfToken = $('meta[name="csrf-token"]').attr('content') xhr.setRequestHeader('X-CSRF-Token', csrfToken) // This will collect patches to publish to `onResponse` var responseData = {} // It seems like `onprogress` was called once with the first _two_ patches. // Track the index to make sure we don't miss any double-patches. var nextPatchIdx = 0 var _this = this xhr.onprogress = function () { // responseText grows; we only care about the most recent patch // TODO: it's a waste to split the text over and over, can // we maintain a indicator to the last-read patch? var patchStrings = xhr.responseText.split("\n\n") while (patchStrings.length > nextPatchIdx) { var nextPatchString = patchStrings[nextPatchIdx] var nextPatch = JSON.parse(nextPatchString) _this._mergePatch(responseData, nextPatch) nextPatchIdx += 1 } onResponse(responseData) } xhr.send(JSON.stringify({ query: queryString, variables: variables, })) }, // merge `patch` into `responseData` (destructive) _mergePatch: function(responseData, patch) { if (patch.path.length === 0) { Object.assign(responseData, patch.value) } else { var targetHash = responseData var steps = patch.path.slice(0, patch.path.length - 1) var lastKey = patch.path[patch.path.length - 1] steps.forEach(function(step) { var nextStep = targetHash[step] if (nextStep == null) { nextStep = targetHash[step] = {} } targetHash = nextStep }) targetHash[lastKey] = patch.value } }
}