Skip to content

Commit 3701d0e

Browse files
fix: Do not modify input params. This closes #230 (#231)
* fix: Do not modify input params. This closes #230 * added test
1 parent cb4b147 commit 3701d0e

File tree

2 files changed

+33
-13
lines changed

2 files changed

+33
-13
lines changed

lib/client.js

+5-13
Original file line numberDiff line numberDiff line change
@@ -32,27 +32,19 @@ const retry = require('async-retry')
3232
*
3333
*/
3434
const rp = opts => {
35+
let url = opts.url
3536
if (opts.qs) {
36-
// we turn the qs struct into a query string over the url
37-
let first = true
38-
for (let key in opts.qs) {
39-
const str = `${encodeURIComponent(key)}=${encodeURIComponent(opts.qs[key])}`
40-
if (first) {
41-
opts.url += `?${str}`
42-
first = false
43-
} else {
44-
opts.url += `&${str}`
45-
}
46-
}
37+
url += '?' + Object.keys(opts.qs)
38+
.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(opts.qs[key])}`)
39+
.join('&')
4740
}
48-
4941
// it appears that certain call paths from our code do not set the
5042
// opts.json field to true; rp is apparently more resilient to
5143
// this situation than needle
5244
opts.json = true
5345

5446
return needle(opts.method.toLowerCase(), // needle takes e.g. 'put' not 'PUT'
55-
opts.url,
47+
url,
5648
opts.body || opts.params,
5749
opts)
5850
.then(resp => {

test/unit/client.test.js

+28
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,34 @@ test('should handle errors even after retries', async t => {
108108
mock.interceptors.forEach(nock.removeInterceptor)
109109
})
110110

111+
test('should retry with same url + querystring', async t => {
112+
const calledUrls = []
113+
const retrySpy = sinon.spy((error) => {
114+
if (error && error.options) {
115+
calledUrls.push(error.options.url)
116+
}
117+
})
118+
const client = new Client({ api_key: 'secret', apihost: 'test_host', proxy: '', retry: { retries: 3, onRetry: retrySpy } })
119+
const METHOD = 'GET'
120+
const PATH = '/dont/add/to/querystring'
121+
const options = { qs: { bob: 'your uncle' } }
122+
const mock = nock('https://test_host')
123+
.get(PATH)
124+
.query({ bob: 'your uncle' })
125+
.times(4)
126+
.replyWithError('simulated error')
127+
.get(PATH).times(1).reply(200, 'not enough retries to come here')
128+
129+
const error = await t.throwsAsync(client.request(METHOD, PATH, options))
130+
t.truthy(error.message)
131+
t.assert(error.message.includes('simulated error'))
132+
t.assert(calledUrls.length === 3)
133+
t.assert(calledUrls[0] === calledUrls[1])
134+
t.assert(calledUrls[0] === calledUrls[2])
135+
136+
mock.interceptors.forEach(nock.removeInterceptor)
137+
})
138+
111139
// end client request tests
112140

113141
test('should use default constructor options', t => {

0 commit comments

Comments
 (0)