Reputation: 6384
I try to create two distinct routes:
What I'm trying :
app.param(function (name) {
return function(req,res,next,id) {
//do some stuff here with id
next();
};
});
app.param('shortId', /[0-9]{0,4}/);
app.param('longId', /[0-9]{5,20}/);
app.get('/path/:shortId', function(req, res){
res.send('ShortID:' + req.params.shortId);
});
app.get('/path/:longId', function(req, res){
res.send('LongId:' + req.params.longId);
});
I always obtain a hit from the first path (shortId) even with a number longer than 4 digits. Do someone has an idea of what I'm doing incorrectly here ?
Upvotes: 2
Views: 1566
Reputation: 6384
It seems that Express match the first expression partially. It is not intuitive, but it still possible to obtain the wanted result by checking "manually" :
app.param(function (name,fn) {
if (fn instanceof RegExp) {
//fn is the regexp that I can use here
return function(req,res,next,id) {
if ( String(id).match(fn) ) {
//do some stuff here with id
next();
}
else {
next('route');
}
};
}
});
As said by bduran, the correct regexps are :
app.param('shortId', /^[0-9]{0,4}$/);
app.param('longId', /^[0-9]{5,20}$/);
Upvotes: 1
Reputation: 180927
You don't really need express-params for this, you can just append a parenthesized regex directly to the parameter;
app.get('/path/:shortId([0-9]{0,4})', function(req, res){
res.send('ShortID:' + req.params.shortId);
});
app.get('/path/:longId([0-9]{5,20})', function(req, res){
res.send('LongId:' + req.params.longId);
});
EDIT:
To make express-params work, there are two things that cause problems in your existing example.
As others have pointed out, you'll need to anchor your regular expressions using /^...$/
, or the first expression will partially match the parameter and always be taken.
Your first app.param call (where you pass the function) always returns a function which means overriding the other app.param calls to use the function for matching instead of the regex. Since the function always calls the parameterless next()
, it always accepts all patterns.
Changing that would result in something like;
app.param(function (name, param) {
if(name != 'veryshortid') // Use this function for veryshortid only
return;
return function(req,res,next,id) {
if(id.length > param) next('route'); // No match, skip
else next(); // Accept
};
});
app.param('veryshortid', 1);
app.param('shortid', /^[0-9]{2,4}$/);
app.param('longid', /^[0-9]{5,20}$/);
app.get('/path/:veryshortid', function(req, res, next){
res.send('VeryShortID:' + req.params.veryshortid);
});
app.get('/path/:shortid', function(req, res, next){
res.send('ShortID:' + req.params.shortid);
});
app.get('/path/:longid', function(req, res, next){
res.send('LongId:' + req.params.longid);
});
Upvotes: 3
Reputation: 3404
It's because in Express logic the first regular expression match the longId
, although partially. Be more restrictive and everything will go fine:
app.param('shortId', /^[0-9]{0,4}$/);
app.param('longId', /^[0-9]{5,20}$/);
Edited:
Also you can change the order in what you load the routes, but it's messy and cheap. Be restrictive ever, marking the beginning and the end of the regular expressions.
Upvotes: 1