good-guy-http
Advanced tools
Comparing version 1.4.1 to 1.4.2
var _ = require('underscore'); | ||
var QueryString = require('request/lib/querystring').Querystring; | ||
module.exports = requestKey; | ||
@@ -15,6 +17,19 @@ | ||
// extract relevant parts of the request | ||
var url = req.url, | ||
method = req.method, | ||
accept = req.headers['accept'], | ||
qs = req.qs; | ||
// a special consideration for the 'qs' and related options in the request lib | ||
// we use their own implementation to generate the correct query string and use | ||
// it as part of our key | ||
if (qs) { | ||
var reqLibStringifier = new QueryString(req); | ||
reqLibStringifier.init(req); | ||
url += "?" + reqLibStringifier.stringify(qs); | ||
} | ||
// for now, we just use a combination of method, url and 'Accept' header as cache key | ||
// this does not work well with Vary - but well enough for most purposes | ||
var url = req.url, method = req.method, accept = req.headers['accept']; | ||
var keyComponents = [method, url]; | ||
@@ -25,4 +40,5 @@ if (accept) { | ||
return keyComponents.join('|'); | ||
} | ||
var requestLib = require('request'); | ||
var Promise = require('bluebird'); | ||
var _ = require('underscore'); | ||
var retryPromise = require('./promise-utils').retryPromise; | ||
var collapsePromises = require('./promise-utils').collapsePromises; | ||
var timeoutPromise = require('./promise-utils').timeoutPromise; | ||
var circuitBreaking = require('./circuit-breaking'); | ||
@@ -34,2 +30,5 @@ | ||
// pass constructor to use other Promise library, string 'default' means bluebird will be used | ||
usePromise: 'default', | ||
// how should we treat 4xx errors - by default, we cache them since they're client errors | ||
@@ -64,2 +63,3 @@ // and are unlikely to fix themselves if we repeat the request | ||
'postprocess', | ||
'usePromise', | ||
@@ -93,2 +93,13 @@ 'mockTimer' | ||
var Promise = config.usePromise; | ||
if (Promise === 'default') { | ||
Promise = require('bluebird'); | ||
} | ||
var promiseUtils = require('./promise-utils')(Promise); | ||
var retryPromise = promiseUtils.retryPromise; | ||
var collapsePromises = promiseUtils.collapsePromises; | ||
var timeoutPromise = promiseUtils.timeoutPromise; | ||
// set all the components up | ||
@@ -105,3 +116,3 @@ var request = requestLib.defaults(reqConfig); | ||
// we obviously aren't allowed to retry POST's and other non-idempotent requests | ||
var fetch = require('./promised-request')(request); | ||
var fetch = require('./promised-request')(request, Promise); | ||
var fetchIdempotent = fetch, fetchNonIdempotent = fetch; | ||
@@ -108,0 +119,0 @@ if (config.maxRetries) |
@@ -1,56 +0,63 @@ | ||
var Promise = require('bluebird'); | ||
var util = require('util'); | ||
module.exports.collapsePromises = function(fn, keyFn) { | ||
keyFn = keyFn || concatenateArguments; | ||
var existingPromises = {}; | ||
module.exports = function (Promise) { | ||
function collapsePromises(fn, keyFn) { | ||
keyFn = keyFn || concatenateArguments; | ||
var existingPromises = {}; | ||
return function() { | ||
var key = keyFn([].slice.apply(arguments)); | ||
if (existingPromises[key]) | ||
return existingPromises[key]; | ||
return function() { | ||
var key = keyFn([].slice.apply(arguments)); | ||
if (existingPromises[key]) | ||
return existingPromises[key]; | ||
var promise = existingPromises[key] = fn.apply(null, arguments).then(function(result) { | ||
delete existingPromises[key]; | ||
return result; | ||
}).catch(function(err) { | ||
delete existingPromises[key]; | ||
throw err; | ||
}); | ||
return promise; | ||
}; | ||
}; | ||
var promise = existingPromises[key] = fn.apply(null, arguments).then(function(result) { | ||
delete existingPromises[key]; | ||
return result; | ||
}).catch(function(err) { | ||
delete existingPromises[key]; | ||
throw err; | ||
}); | ||
return promise; | ||
}; | ||
} | ||
module.exports.retryPromise = function(fn, retries) { | ||
return function() { | ||
var args = [].slice.apply(arguments); | ||
function retryPromise(fn, retries) { | ||
return function() { | ||
var args = [].slice.apply(arguments); | ||
return new Promise(function(resolve, reject) { | ||
tryOnce(retries); | ||
return new Promise(function(resolve, reject) { | ||
tryOnce(retries); | ||
function tryOnce(triesRemaining) { | ||
fn.apply(null, args).then(function(result) { | ||
resolve(result); | ||
}).catch(function(err) { | ||
if (triesRemaining > 0 && (!err.unretriable)) | ||
tryOnce(triesRemaining - 1); | ||
else | ||
reject(err); | ||
}); | ||
} | ||
}); | ||
}; | ||
}; | ||
function tryOnce(triesRemaining) { | ||
fn.apply(null, args).then(function(result) { | ||
resolve(result); | ||
}).catch(function(err) { | ||
if (triesRemaining > 0 && (!err.unretriable)) | ||
tryOnce(triesRemaining - 1); | ||
else | ||
reject(err); | ||
}); | ||
} | ||
}); | ||
}; | ||
} | ||
module.exports.timeoutPromise = function(fn, timeout) { | ||
return function() { | ||
var args = [].slice.apply(arguments); | ||
return new Promise(function(resolve, reject) { | ||
setTimeout(function() { | ||
reject(new TimeoutError("Timeout expired.")); | ||
}, timeout); | ||
function timeoutPromise(fn, timeout) { | ||
return function() { | ||
var args = [].slice.apply(arguments); | ||
return new Promise(function(resolve, reject) { | ||
setTimeout(function() { | ||
reject(new TimeoutError("Timeout expired.")); | ||
}, timeout); | ||
fn.apply(null, args).then(resolve).catch(reject); | ||
}); | ||
fn.apply(null, args).then(resolve).catch(reject); | ||
}); | ||
}; | ||
} | ||
return { | ||
collapsePromises: collapsePromises, | ||
retryPromise: retryPromise, | ||
timeoutPromise: timeoutPromise | ||
}; | ||
@@ -57,0 +64,0 @@ }; |
@@ -1,2 +0,1 @@ | ||
var Promise = require('bluebird'); | ||
var Response = require('./response'); | ||
@@ -7,3 +6,3 @@ var HttpError = require('./http-error'); | ||
function promisedRequests(request) { | ||
function promisedRequests(request, Promise) { | ||
return makePromisedRequest; | ||
@@ -10,0 +9,0 @@ |
{ | ||
"name": "good-guy-http", | ||
"version": "1.4.1", | ||
"version": "1.4.2", | ||
"description": "The opinionated sane HTTP client with a good guy approach.", | ||
@@ -30,2 +30,3 @@ "main": "lib/index.js", | ||
"mocha": "^2.3.2", | ||
"q": "^1.4.1", | ||
"sinon": "^1.16.1", | ||
@@ -32,0 +33,0 @@ "supertest": "^1.1.0" |
@@ -53,2 +53,5 @@ # good-guy-http | ||
usePromise: require('bluebird'), // Promise constructor to use, you may want to replace bluebird with | ||
// different implementation, like q or native Promise | ||
defaultCaching: { // default caching settings for responses without Cache-Control | ||
@@ -55,0 +58,0 @@ cached: true, // - whether such responses should be cached at all |
@@ -5,5 +5,6 @@ var assert = require('assert'); | ||
var retryPromise = require('../../lib/promise-utils').retryPromise; | ||
var collapsePromises = require('../../lib/promise-utils').collapsePromises; | ||
var timeoutPromise = require('../../lib/promise-utils').timeoutPromise; | ||
var promiseUtils = require('../../lib/promise-utils')(Promise); | ||
var retryPromise = promiseUtils.retryPromise; | ||
var collapsePromises = promiseUtils.collapsePromises; | ||
var timeoutPromise = promiseUtils.timeoutPromise; | ||
@@ -10,0 +11,0 @@ var expectRejection = require('./../helpers').expectRejection; |
@@ -8,3 +8,3 @@ var request = require('request'); | ||
var app = require('./../test-app/test-app')(); | ||
var req = require('../../lib/promised-request')(request.defaults({timeout: 500})); | ||
var req = require('../../lib/promised-request')(request.defaults({timeout: 500}), Promise); | ||
@@ -11,0 +11,0 @@ before(function(done) { |
@@ -16,2 +16,7 @@ var assert = require('assert'); | ||
it("should handle the 'qs' parameter correctly", function() { | ||
var req = canonicalizeRequest({url: 'http://example.org', qs: {a: 1, b: 2}}); | ||
assert.equal(requestKey(req), 'GET|http://example.org?a=1&b=2'); | ||
}); | ||
it("should include accept header if provided", function() { | ||
@@ -18,0 +23,0 @@ var req = canonicalizeRequest({url: 'http://example.org', headers: {'AcCePt': 'application/json'}}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
83091
46
1966
144
8