Skip to content

Commit

Permalink
Expose xhr object for aborts (#144)
Browse files Browse the repository at this point in the history
  • Loading branch information
Vijar committed May 6, 2016
1 parent 0fa480a commit 7a82aaa
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 23 deletions.
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,32 @@ fetcher
});
```

## XHR Object

The xhr object is returned by the `.end()` method as long as you're *not* chaining promises.
This is useful if you want to abort a request before it is completed.

```js
var req = fetcher
.read('someData')
.params({id: ###})
.end(function (err, data, meta) {
// err.output will be { message: "Not found", more: "meta data" }
});
// req is the xhr object
req.abort();
```

However, you can't acces the xhr object if using promise chaining like so:
```js
var req = fetcher
.read('someData')
.params({id: ###})
.end();
// req is a promise
req.then(onResolve, onReject);
```

## XHR Timeouts

`xhrTimeout` is an optional config property that allows you to set timeout (in ms) for all clientside requests, defaults to `3000`.
Expand Down
31 changes: 14 additions & 17 deletions libs/fetcher.client.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,30 +132,27 @@ Request.prototype.clientConfig = function (config) {
*/
Request.prototype.end = function (callback) {
var self = this;
var promise = new Promise(function (resolve, reject) {
debug('Executing request %s.%s with params %o and body %o', self.resource, self.operation, self._params, self._body);
setImmediate(executeRequest, self, resolve, reject);
});

promise = promise.then(function (result) {
if (result.meta) {
self.options._serviceMeta.push(result.meta);
}
return result;
}, function(errData) {
if (errData.meta) {
self.options._serviceMeta.push(errData.meta);
function captureMeta (data) {
if (data.meta) {
self.options._serviceMeta.push(data.meta);
}
throw errData;
});
return data;
}

if (callback) {
promise.then(function (result) {
return executeRequest(self, function (result) {
captureMeta(result);
setImmediate(callback, null, result.data, result.meta);
}, function (err) {
captureMeta(err);
setImmediate(callback, err);
});
} else {
var promise = new Promise(function (resolve, reject) {
debug('Executing request %s.%s with params %o and body %o', self.resource, self.operation, self._params, self._body);
setImmediate(executeRequest, self, resolve, reject);
});
promise = promise.then(captureMeta, captureMeta);
return promise;
}
};
Expand Down Expand Up @@ -238,7 +235,7 @@ function executeRequest (request, resolve, reject) {
}; // TODO: remove. leave here for now for backward compatibility
uri = request._constructGroupUri(uri);
allow_retry_post = (request.operation === OP_READ);
REST.post(uri, {}, data, lodash.merge({unsafeAllowRetry: allow_retry_post, xhrTimeout: request.options.xhrTimeout}, clientConfig), function postDone(err, response) {
return REST.post(uri, {}, data, lodash.merge({unsafeAllowRetry: allow_retry_post, xhrTimeout: request.options.xhrTimeout}, clientConfig), function postDone(err, response) {
if (err) {
debug('Syncing ' + request.resource + ' failed: statusCode=' + err.statusCode, 'info');
return reject(err);
Expand Down
12 changes: 6 additions & 6 deletions libs/util/http.client.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,11 +159,11 @@ function doXhr(method, url, headers, data, config, callback) {
if (data !== undefined && data !== NULL) {
options.data = isContentTypeJSON(headers) ? JSON.stringify(data) : data;
}
io(url, options);
return io(url, options);
}

function io(url, options) {
xhr({
return xhr({
url: url,
method: options.method || METHOD_GET,
timeout: options.timeout,
Expand Down Expand Up @@ -233,7 +233,7 @@ module.exports = {
* @param {Function} callback The callback function, with two params (error, response)
*/
get : function (url, headers, config, callback) {
doXhr(METHOD_GET, url, headers, NULL, config, callback);
return doXhr(METHOD_GET, url, headers, NULL, config, callback);
},

/**
Expand All @@ -249,7 +249,7 @@ module.exports = {
* @param {Function} callback The callback function, with two params (error, response)
*/
put : function (url, headers, data, config, callback) {
doXhr(METHOD_PUT, url, headers, data, config, callback);
return doXhr(METHOD_PUT, url, headers, data, config, callback);
},

/**
Expand All @@ -266,7 +266,7 @@ module.exports = {
* @param {Function} callback The callback function, with two params (error, response)
*/
post : function (url, headers, data, config, callback) {
doXhr(METHOD_POST, url, headers, data, config, callback);
return doXhr(METHOD_POST, url, headers, data, config, callback);
},

/**
Expand All @@ -281,6 +281,6 @@ module.exports = {
* @param {Function} callback The callback function, with two params (error, response)
*/
'delete' : function (url, headers, config, callback) {
doXhr(METHOD_DELETE, url, headers, NULL, config, callback);
return doXhr(METHOD_DELETE, url, headers, NULL, config, callback);
}
};
46 changes: 46 additions & 0 deletions tests/unit/libs/fetcher.client.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,52 @@ describe('Client Fetcher', function () {
})
});

describe('xhr', function () {
before(function () {
this.fetcher = new Fetcher({
context: context
});
});

it('should return xhr object when calling end w/ callback', function (done) {
var operation = 'create';
var xhr = this.fetcher
[operation](resource)
.params(params)
.body(body)
.clientConfig(config)
.end(callback(operation, function (err) {
if (err) {
done(err);
return;
}
console.log(xhr.readyState);
expect(xhr.readyState).to.exist;
expect(xhr.abort).to.exist;
expect(xhr.open).to.exist;
expect(xhr.send).to.exist;
done();
}));
});
it('should be able to abort xhr when calling end w/ callback', function (done) {
var operation = 'create';
var xhr = this.fetcher
[operation](resource)
.params(params)
.body(body)
.clientConfig(config)
.end(callback(operation, function (err) {
if (err) {
// in this case, an error is good
// we want the error to be thrown then request is aborted
done();
}
}));
expect(xhr.abort).to.exist;
xhr.abort();
});
});

describe('xhrTimeout', function () {
var DEFAULT_XHR_TIMEOUT = 3000;

Expand Down

0 comments on commit 7a82aaa

Please sign in to comment.