Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

balexandre patch 1684 #1702

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
39 changes: 39 additions & 0 deletions lib/router.js
Expand Up @@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could add an example here, the new API site would render it to the website.
Like:

@example
server.get( { name: 'cities', path: '/countries/:name/states/:state/cities' }, (req, res, next) => ...);
var cities = server.router.render('cities', {  name: 'Australia', state: 'New South Wales' });
// cities:  '/countries/Australia/states/New%20South%20Wales/cities'

*/
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.
*
Expand Down
136 changes: 135 additions & 1 deletion test/router.test.js
Expand Up @@ -26,9 +26,143 @@ 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' }, 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 <cities> is missing parameter <state>');
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should throw if we catch branch doesn't run


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');
Expand Down