From 608225ca144c49928cbbe239eea25e602cb1cbef Mon Sep 17 00:00:00 2001 From: Horia Radu Date: Thu, 21 Jul 2016 13:06:12 +0300 Subject: [PATCH] Stringify query params which are objects as JSON Stringify query params which are objects in a way in which empty ararys are preserved instead of removed (default querystring implementation). fix: https://github.com/strongloop/strong-remoting/issues/324 --- lib/http-invocation.js | 8 ++- test/http-invocation.test.js | 124 +++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+), 1 deletion(-) diff --git a/lib/http-invocation.js b/lib/http-invocation.js index 0839dcf..ccccf06 100644 --- a/lib/http-invocation.js +++ b/lib/http-invocation.js @@ -146,7 +146,13 @@ HttpInvocation.prototype._processArg = function(req, verb, query, accept) { // default to query string for GET if (val !== undefined) { query = query || {}; - query[name] = val; + + if ((accept.type === 'object' || accept.type === 'string') && + typeof val === 'object') { + query[name] = JSON.stringify(val); + } else { + query[name] = val; + } } } else { // default to storing args on the body for !GET diff --git a/test/http-invocation.test.js b/test/http-invocation.test.js index 807b88d..c7b42be 100644 --- a/test/http-invocation.test.js +++ b/test/http-invocation.test.js @@ -186,6 +186,122 @@ describe('HttpInvocation', function() { }); }); }); + + describe('createRequest', function() { + it('should create a simple request', function() { + var method = givenSharedStaticMethod(); + method.getEndpoints = function() { + return [createEndpoint()]; + }; + var inv = new HttpInvocation(method, [], [], 'http://base'); + + var expectedReq = { method: 'GET', + url: 'http://base/testModel/testMethod', + protocol: 'http:', + json: true, + }; + expect(inv.createRequest()).to.eql(expectedReq); + }); + + it('should make primitive type arguments as query params', function() { + var method = givenSharedStaticMethod({ + accepts: [ + { arg: 'a', type: 'number' }, + { arg: 'b', type: 'string' }, + ], + }); + method.getEndpoints = function() { + return [createEndpoint()]; + }; + + var aValue = 2; + var bValue = 'foo'; + var inv = new HttpInvocation(method, [], [aValue, bValue], 'http://base'); + + var expectedReq = { method: 'GET', + url: 'http://base/testModel/testMethod?a=2&b=foo', + protocol: 'http:', + json: true, + }; + expect(inv.createRequest()).to.eql(expectedReq); + }); + + it('should make an array argument as a query param', function() { + var method = givenSharedStaticMethod({ + accepts: [ + { arg: 'a', type: 'object' }, + ], + }); + method.getEndpoints = function() { + return [createEndpoint()]; + }; + + var aValue = [1, 2, 3]; + var inv = new HttpInvocation(method, [], [aValue], 'http://base'); + + var expectedReq = { method: 'GET', + url: 'http://base/testModel/testMethod?a=' + encodeURIComponent('[1,2,3]'), + protocol: 'http:', + json: true, + }; + expect(inv.createRequest()).to.eql(expectedReq); + }); + + it('should keep an empty array as a query param', function() { + var method = givenSharedStaticMethod({ + accepts: [ + { arg: 'a', type: 'object' }, + ], + }); + method.getEndpoints = function() { + return [createEndpoint()]; + }; + + var aValue = []; + var inv = new HttpInvocation(method, [], [aValue], 'http://base'); + + var expectedReq = { method: 'GET', + url: 'http://base/testModel/testMethod?a=' + encodeURIComponent('[]'), + protocol: 'http:', + json: true, + }; + expect(inv.createRequest()).to.eql(expectedReq); + }); + + it('should handle a loopback filter as a query param', function() { + var method = givenSharedStaticMethod({ + accepts: [ + { arg: 'filter', type: 'object' }, + ], + }); + method.getEndpoints = function() { + return [createEndpoint()]; + }; + + var filter = { + where: { + id: { + inq: [1, 2], + }, + typeId: { + inq: [], + }, + }, + include: ['related'], + }; + var inv = new HttpInvocation(method, [], [filter], 'http://base'); + + var expectedFilter = + '{"where":{"id":{"inq":[1,2]},"typeId":{"inq":[]}},"include":["related"]}'; + var expectedReq = { method: 'GET', + url: 'http://base/testModel/testMethod?filter=' + + encodeURIComponent(expectedFilter), + protocol: 'http:', + json: true, + }; + expect(inv.createRequest()).to.eql(expectedReq); + }); + }); }); function givenSharedStaticMethod(fn, config) { @@ -200,3 +316,11 @@ function givenSharedStaticMethod(fn, config) { extend(testClass.testMethod, config); return SharedMethod.fromFunction(fn, 'testStaticMethodName', null, true); } + +function createEndpoint(config) { + config = config || {}; + return { + verb: config.verb || 'GET', + fullPath: config.fullPath || '/testModel/testMethod', + }; +}