From 2961db95944b8a9a67f2bf5b5c0a3b35fc64cd0a Mon Sep 17 00:00:00 2001 From: Ryan Olf Date: Sat, 31 Mar 2018 17:46:46 -0700 Subject: [PATCH 1/2] Client.get() will respect existing query parameters in url --- lib/transports/http.js | 4 ++-- tests/transports/http.js | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/lib/transports/http.js b/lib/transports/http.js index d7cb717..38a4489 100644 --- a/lib/transports/http.js +++ b/lib/transports/http.js @@ -104,8 +104,8 @@ 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)) return { url: parsedUrl.toString(), diff --git a/tests/transports/http.js b/tests/transports/http.js index a92e3ec..06141d4 100644 --- a/tests/transports/http.js +++ b/tests/transports/http.js @@ -108,6 +108,25 @@ 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 path params', function () { const url = 'http://www.example.com/{user}/' const fields = [new document.Field('user', true, 'path')] @@ -244,6 +263,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')] From c8ae30e925cd44de81e1cc8bfc9821b9fb64a82f Mon Sep 17 00:00:00 2001 From: Ryan Olf Date: Tue, 1 May 2018 14:09:42 -0700 Subject: [PATCH 2/2] Query parameters of type Array stringified to repeated key,value pairs --- lib/transports/http.js | 30 +++++++++++++++++++++++++++++- tests/transports/http.js | 17 +++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/lib/transports/http.js b/lib/transports/http.js index d7cb717..ffcb2c0 100644 --- a/lib/transports/http.js +++ b/lib/transports/http.js @@ -107,8 +107,36 @@ class HTTPTransport { parsedUrl = new URL(parsedUrl) parsedUrl.set('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..9bb15d6 100644 --- a/tests/transports/http.js +++ b/tests/transports/http.js @@ -108,6 +108,23 @@ describe('Test the HTTPTransport', function () { }) }) + 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')]