diff --git a/lib/transports/http.js b/lib/transports/http.js index d7cb717..2298dc1 100644 --- a/lib/transports/http.js +++ b/lib/transports/http.js @@ -104,11 +104,39 @@ class HTTPTransport { let parsedUrl = urlTemplate.parse(link.url) parsedUrl = parsedUrl.expand(pathParams) - parsedUrl = new URL(parsedUrl) - parsedUrl.set('query', queryParams) + parsedUrl = new URL(parsedUrl, null, true) + parsedUrl.set('query', Object.assign(parsedUrl.query, queryParams)) + + // Modified querystringify to parse lists into repeated querystring keys + function querystringify (obj, prefix) { + var has = Object.prototype.hasOwnProperty + prefix = prefix || '' + + var pairs = [] + + // + // Optionally prefix with a '?' if needed + // + if (typeof prefix !== 'string') prefix = '?' + + for (var key in obj) { + if (has.call(obj, key)) { + let value = obj[key] + if (Array.isArray(value)) { + for (let item of value) { + pairs.push(encodeURIComponent(key) + '=' + encodeURIComponent(item)) + } + } else { + pairs.push(encodeURIComponent(key) + '=' + encodeURIComponent(value)) + } + } + } + + return pairs.length ? prefix + pairs.join('&') : '' + } return { - url: parsedUrl.toString(), + url: parsedUrl.toString(querystringify), options: requestOptions } } diff --git a/tests/transports/http.js b/tests/transports/http.js index a92e3ec..a7c09cc 100644 --- a/tests/transports/http.js +++ b/tests/transports/http.js @@ -108,6 +108,42 @@ describe('Test the HTTPTransport', function () { }) }) + it('should check the action function of an HTTP transport (json) with query params and existing querystring in url', function () { + const url = 'http://www.example.com/?next=2' + const fields = [new document.Field('page', false, 'query')] + const link = new document.Link(url, 'get', 'application/json', fields) + const transport = new transports.HTTPTransport({ + fetch: testUtils.echo + }) + const params = { + page: 23 + } + + return transport.action(link, decoders, params) + .then((res) => { + expect(res.url).toMatch(/http:\/\/www.example.com\/\?(page=23&(?=next=2)|next=2&(?=page=23))/) + expect(res).toHaveProperty('headers', {}) + expect(res).toHaveProperty('method', 'GET') + }) + }) + + it('should check the action function of an HTTP transport (json) with list-type query params', function () { + const url = 'http://www.example.com/' + const fields = [new document.Field('pages', false, 'query')] + const link = new document.Link(url, 'get', 'application/json', fields) + const transport = new transports.HTTPTransport({ + fetch: testUtils.echo + }) + const params = { + pages: [22, 23] + } + + return transport.action(link, decoders, params) + .then((res) => { + expect(res).toEqual({url: 'http://www.example.com/?pages=22&pages=23', headers: {}, method: 'GET'}) + }) + }) + it('should check the action function of an HTTP transport (json) with path params', function () { const url = 'http://www.example.com/{user}/' const fields = [new document.Field('user', true, 'path')] @@ -244,6 +280,21 @@ describe('Test the HTTPTransport', function () { }) }) + it('should check the action function of an HTTP transport (json) with querystring in url and missing optional query params', function () { + const url = 'http://www.example.com/?next=1' + const fields = [new document.Field('page', false, 'query')] + const link = new document.Link(url, 'get', 'application/json', fields) + const transport = new transports.HTTPTransport({ + fetch: testUtils.echo + }) + const params = {} + + return transport.action(link, decoders, params) + .then((res) => { + expect(res).toEqual({url: 'http://www.example.com/?next=1', headers: {}, method: 'GET'}) + }) + }) + it('should check the action function of an HTTP transport (json) with missing required parameter', function () { const url = 'http://www.example.com/{user}/' const fields = [new document.Field('user', true, 'path')]