From 0de7411bd4a041e25e38b22308affde14a0db55e Mon Sep 17 00:00:00 2001 From: Bruno Alexandre Date: Tue, 11 Sep 2018 13:30:23 +0200 Subject: [PATCH 1/4] bring back server.router.render Took the base code from latest version 6 and applied the version 7 routing. fixes #1684 --- lib/router.js | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/lib/router.js b/lib/router.js index 10c4a2dd9..662f6e74f 100644 --- a/lib/router.js +++ b/lib/router.js @@ -114,6 +114,45 @@ Router.prototype.lookupByName = function lookupByName(name, req, res) { return route.chain.run.bind(route.chain); }; +/** + * Takes an object of route params and query params, and 'renders' a URL. + * + * @public + * @function render + * @param {String} routeName - the route name + * @param {Object} params - an object of route params + * @param {Object} query - an object of query params + * @returns {String} URL + */ +Router.prototype.render = function render(routeName, params, query) { + var self = this; + + function pathItem(match, key) { + if (params.hasOwnProperty(key) === false) { + throw new Error( + 'Route <' + routeName + '> is missing parameter <' + key + '>' + ); + } + return '/' + encodeURIComponent(params[key]); + } + + function queryItem(key) { + return encodeURIComponent(key) + '=' + encodeURIComponent(query[key]); + } + + var route = self._registry.get()[routeName]; + + if (!route) { + return null; + } + + var _path = route.spec.path; + var _url = _path.replace(/\/:([A-Za-z0-9_]+)(\([^\\]+?\))?/g, pathItem); + var items = Object.keys(query || {}).map(queryItem); + var queryString = items.length > 0 ? '?' + items.join('&') : ''; + return _url + queryString; +}; + /** * Adds a route. * From b57e6f37567db0f684b815c7f070c9f7f0b10de1 Mon Sep 17 00:00:00 2001 From: Bruno Alexandre Date: Tue, 11 Sep 2018 13:51:40 +0200 Subject: [PATCH 2/4] bring back tests for render route --- test/router.test.js | 132 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) diff --git a/test/router.test.js b/test/router.test.js index 002f60017..8c00cef8f 100644 --- a/test/router.test.js +++ b/test/router.test.js @@ -29,6 +29,138 @@ var mockRes = { ///--- Tests +test('render route', function(t) { + var server = restify.createServer(); + server.get({ name: 'countries', path: '/countries' }, mockResponse); + server.get({ name: 'country', path: '/countries/:name' }, mockResponse); + server.get( + { name: 'cities', path: '/countries/:name/states/:state/cities' }, + mockResponse + ); + + var countries = server.router.render('countries', {}); + t.equal(countries, '/countries'); + + var country = server.router.render('country', { name: 'Australia' }); + t.equal(country, '/countries/Australia'); + + var cities = server.router.render('cities', { + name: 'Australia', + state: 'New South Wales' + }); + t.equal(cities, '/countries/Australia/states/New%20South%20Wales/cities'); + + t.end(); +}); + +test('render route (missing params)', function(t) { + var server = restify.createServer(); + server.get( + { name: 'cities', path: '/countries/:name/states/:state/cities' }, + mockResponse + ); + + try { + server.router.render('cities', { name: 'Australia' }); + } catch (ex) { + t.equal(ex, 'Error: Route is missing parameter '); + } + + t.end(); +}); + +test('GH #704: render route (special charaters)', function(t) { + var server = restify.createServer(); + server.get({ name: 'my-route', path: '/countries/:name' }, mockResponse); + + var link = server.router.render('my-route', { name: 'Australia' }); + t.equal(link, '/countries/Australia'); + + t.end(); +}); + +test('GH #704: render route (with sub-regex param)', function(t) { + var server = restify.createServer(); + server.get( + { + name: 'my-route', + path: '/countries/:code([A-Z]{2,3})' + }, + mockResponse + ); + + var link = server.router.render('my-route', { code: 'FR' }); + t.equal(link, '/countries/FR'); + + link = server.router.render('my-route', { code: '111' }); + t.equal(link, '/countries/111'); + t.end(); +}); + +test('GH-796: render route (with multiple sub-regex param)', function(t) { + var server = restify.createServer(); + server.get( + { + name: 'my-route', + path: '/countries/:code([A-Z]{2,3})/:area([0-9]+)' + }, + mockResponse + ); + + var link = server.router.render('my-route', { code: '111', area: 42 }); + t.equal(link, '/countries/111/42'); + t.end(); +}); + +test('render route (with encode)', function(t) { + var server = restify.createServer(); + server.get({ name: 'my-route', path: '/countries/:name' }, mockResponse); + + var link = server.router.render('my-route', { name: 'Trinidad & Tobago' }); + t.equal(link, '/countries/Trinidad%20%26%20Tobago'); + + t.end(); +}); + +test('render route (query string)', function(t) { + var server = restify.createServer(); + server.get({ name: 'country', path: '/countries/:name' }, mockResponse); + + var country1 = server.router.render( + 'country', + { + name: 'Australia' + }, + { + state: 'New South Wales', + 'cities/towns': 5 + } + ); + + t.equal( + country1, + '/countries/Australia?state=New%20South%20Wales&cities%2Ftowns=5' + ); + + var country2 = server.router.render( + 'country', + { + name: 'Australia' + }, + { + state: 'NSW & VIC', + 'cities&towns': 5 + } + ); + + t.equal( + country2, + '/countries/Australia?state=NSW%20%26%20VIC&cities%26towns=5' + ); + + t.end(); +}); + test('mounts a route', function(t) { function handler(req, res, next) { res.send('Hello world'); From 70bb1f2cfa63e64ca38d289ddce0798987b5e7fb Mon Sep 17 00:00:00 2001 From: Bruno Alexandre Date: Tue, 11 Sep 2018 14:17:12 +0200 Subject: [PATCH 3/4] fixed mockResponse --- test/router.test.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/test/router.test.js b/test/router.test.js index 8c00cef8f..58ec9ca3c 100644 --- a/test/router.test.js +++ b/test/router.test.js @@ -31,11 +31,11 @@ var mockRes = { test('render route', function(t) { var server = restify.createServer(); - server.get({ name: 'countries', path: '/countries' }, mockResponse); - server.get({ name: 'country', path: '/countries/:name' }, mockResponse); + server.get({ name: 'countries', path: '/countries' }, mockRes); + server.get({ name: 'country', path: '/countries/:name' }, mockRes); server.get( { name: 'cities', path: '/countries/:name/states/:state/cities' }, - mockResponse + mockRes ); var countries = server.router.render('countries', {}); @@ -57,7 +57,7 @@ test('render route (missing params)', function(t) { var server = restify.createServer(); server.get( { name: 'cities', path: '/countries/:name/states/:state/cities' }, - mockResponse + mockRes ); try { @@ -71,7 +71,7 @@ test('render route (missing params)', function(t) { test('GH #704: render route (special charaters)', function(t) { var server = restify.createServer(); - server.get({ name: 'my-route', path: '/countries/:name' }, mockResponse); + server.get({ name: 'my-route', path: '/countries/:name' }, mockRes); var link = server.router.render('my-route', { name: 'Australia' }); t.equal(link, '/countries/Australia'); @@ -86,7 +86,7 @@ test('GH #704: render route (with sub-regex param)', function(t) { name: 'my-route', path: '/countries/:code([A-Z]{2,3})' }, - mockResponse + mockRes ); var link = server.router.render('my-route', { code: 'FR' }); @@ -104,7 +104,7 @@ test('GH-796: render route (with multiple sub-regex param)', function(t) { name: 'my-route', path: '/countries/:code([A-Z]{2,3})/:area([0-9]+)' }, - mockResponse + mockRes ); var link = server.router.render('my-route', { code: '111', area: 42 }); @@ -114,7 +114,7 @@ test('GH-796: render route (with multiple sub-regex param)', function(t) { test('render route (with encode)', function(t) { var server = restify.createServer(); - server.get({ name: 'my-route', path: '/countries/:name' }, mockResponse); + server.get({ name: 'my-route', path: '/countries/:name' }, mockRes); var link = server.router.render('my-route', { name: 'Trinidad & Tobago' }); t.equal(link, '/countries/Trinidad%20%26%20Tobago'); @@ -124,7 +124,7 @@ test('render route (with encode)', function(t) { test('render route (query string)', function(t) { var server = restify.createServer(); - server.get({ name: 'country', path: '/countries/:name' }, mockResponse); + server.get({ name: 'country', path: '/countries/:name' }, mockRes); var country1 = server.router.render( 'country', From 45bc116d7a1bdbd5a2b0317c7fa3051fe006c174 Mon Sep 17 00:00:00 2001 From: Bruno Alexandre Date: Tue, 11 Sep 2018 15:04:34 +0200 Subject: [PATCH 4/4] added missing mockResponse method --- test/router.test.js | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/test/router.test.js b/test/router.test.js index 58ec9ca3c..35856b447 100644 --- a/test/router.test.js +++ b/test/router.test.js @@ -26,16 +26,18 @@ var mockRes = { setHeader: function() {}, send: function() {} }; - +var mockResponse = function respond(req, res, next) { + res.send(200); +}; ///--- Tests test('render route', function(t) { var server = restify.createServer(); - server.get({ name: 'countries', path: '/countries' }, mockRes); - server.get({ name: 'country', path: '/countries/:name' }, mockRes); + server.get({ name: 'countries', path: '/countries' }, mockResponse); + server.get({ name: 'country', path: '/countries/:name' }, mockResponse); server.get( { name: 'cities', path: '/countries/:name/states/:state/cities' }, - mockRes + mockResponse ); var countries = server.router.render('countries', {}); @@ -57,7 +59,7 @@ test('render route (missing params)', function(t) { var server = restify.createServer(); server.get( { name: 'cities', path: '/countries/:name/states/:state/cities' }, - mockRes + mockResponse ); try { @@ -71,7 +73,7 @@ test('render route (missing params)', function(t) { test('GH #704: render route (special charaters)', function(t) { var server = restify.createServer(); - server.get({ name: 'my-route', path: '/countries/:name' }, mockRes); + server.get({ name: 'my-route', path: '/countries/:name' }, mockResponse); var link = server.router.render('my-route', { name: 'Australia' }); t.equal(link, '/countries/Australia'); @@ -86,7 +88,7 @@ test('GH #704: render route (with sub-regex param)', function(t) { name: 'my-route', path: '/countries/:code([A-Z]{2,3})' }, - mockRes + mockResponse ); var link = server.router.render('my-route', { code: 'FR' }); @@ -104,7 +106,7 @@ test('GH-796: render route (with multiple sub-regex param)', function(t) { name: 'my-route', path: '/countries/:code([A-Z]{2,3})/:area([0-9]+)' }, - mockRes + mockResponse ); var link = server.router.render('my-route', { code: '111', area: 42 }); @@ -114,7 +116,7 @@ test('GH-796: render route (with multiple sub-regex param)', function(t) { test('render route (with encode)', function(t) { var server = restify.createServer(); - server.get({ name: 'my-route', path: '/countries/:name' }, mockRes); + server.get({ name: 'my-route', path: '/countries/:name' }, mockResponse); var link = server.router.render('my-route', { name: 'Trinidad & Tobago' }); t.equal(link, '/countries/Trinidad%20%26%20Tobago'); @@ -124,7 +126,7 @@ test('render route (with encode)', function(t) { test('render route (query string)', function(t) { var server = restify.createServer(); - server.get({ name: 'country', path: '/countries/:name' }, mockRes); + server.get({ name: 'country', path: '/countries/:name' }, mockResponse); var country1 = server.router.render( 'country',