148

Is there a way to make this on a single function call?

var todo = function (req, res){};

app.get("/", todo);
app.get("/blabla", todo);
app.get("/blablablabla", todo);

Something like:

app.get("/", "/blabla", "/blablablabla", todo );

I know this is a syntax mess, but just for giving an idea of what I would like to achieve, an array of the routes would be awesome!

Anyone know how to do this?

smonff
  • 3,399
  • 3
  • 36
  • 46
Aronis Mariano
  • 2,352
  • 3
  • 22
  • 19
  • 2
    You should be able to write a regular expression that will match all the routes you want to route to todo, and use the regular expression as your endpoint. It may end up looking messy, but it will work. I'm not posting this as an answer as I'm not sure what the regular expression would be, and this is more of a push to that direction. There is mention of using regular expressions in the docs here: http://expressjs.com/api.html#app.VERB – Nick Mitchinson Mar 11 '13 at 22:45
  • i dont have experience with regex in JS... ill give it a try... but any other option is welcome! – Aronis Mariano Mar 11 '13 at 22:48
  • 1
    I dont have much either, which is honestly why I didn't just give it to you, however my understanding is that regular expressions are fairly universaly; Express should parse your expressions pretty much the same as any other language. – Nick Mitchinson Mar 11 '13 at 22:56
  • 1
    Regular expressions are very powerful and definitely worth learning. Here is a solution: app.get(/^\/((blabla){0,2})$/, function(req, resp) { var matched = req.params[0]; resp .set('Content-type', 'text/plain') .send("Matched: '" + matched + "'"); }); A couple of things: 1. regex's begin and end with a /, so any / chars have to be escaped. 2. The ^ char matches the beginning of the string, the $ char matches the end of the string. Without them, the match will succeed even with extraneous chars at the start or end of the path, i.e. /x/blablaxxx – John Deighan Jul 14 '17 at 03:25

5 Answers5

179

I came across this question while looking for the same functionality.

@Jonathan Ong mentioned in a comment above that using arrays for paths is deprecated but it is explicitly described in Express 4, and it works in Express 3.x. Here's an example of something to try:

app.get(
    ['/test', '/alternative', '/barcus*', '/farcus/:farcus/', '/hoop(|la|lapoo|lul)/poo'],
    function ( request, response ) {

    }
);

From inside the request object, with a path of /hooplul/poo?bandle=froo&bandle=pee&bof=blarg:

"route": {
    "keys": [
        {
            "optional": false, 
            "name": "farcus"
        }
    ], 
    "callbacks": [
        null
    ], 
    "params": [
        null, 
        null, 
        "lul"
    ], 
    "regexp": {}, 
    "path": [
        "/test", 
        "/alternative", 
        "/barcus*", 
        "/farcus/:farcus/", 
        "/hoop(|la|lapoo|lul)/poo"
    ], 
    "method": "get"
}, 

Note what happens with params: It is aware of the capture groups and params in all of the possible paths, whether or not they are used in the current request.

So stacking multiple paths via an array can be done easily, but the side-effects are possibly unpredictable if you're hoping to pick up anything useful from the path that was used by way of params or capture groups. It's probably more useful for redundancy/aliasing, in which case it'll work very well.

Edit: Please also see @c24w's answer below.

Edit 2: This is a moderately popular answer. Please keep in mind that ExpressJS, as with most Node.js libraries, is a moveable feast. While the routing above does still work (I'm using it at the moment, a very handy feature), I cannot vouch for the output of the request object (it's certainly different from what I've described). Please test carefully to ensure you get the desired results.

Kevin Teljeur
  • 2,283
  • 1
  • 16
  • 14
  • what if I would like to apply middleware for different path and methods. router.get('/:id', validate.itemExists('unit_status'), unitStatusControllers.findOne); router.put('/:id', [validate.checkPermission('edit:unitstatuses'), validate.itemExists('unit_status')], unitStatusControllers.update); router.delete('/:id', [validate.checkPermission('delete:unitstatuses'), validate.itemExists('unit_status')], unitStatusControllers.remove); As you see here I am calling individual itemExists middleware for Get, Put, Delete. Your solution doesn't include for different methods. Any opinion? – SkyDev Apr 26 '22 at 09:57
  • This probably should be a separate question on StackOverflow. You will need different routings for different methods, my solution is just for highlighting what you can do to stack routings on a single method where you want the same function to be called (including middleware). Middleware is an additional complexity, although there's no reason why you couldn't use the route I've described for middleware, no matter which method. – Kevin Teljeur Apr 28 '22 at 11:41
  • Could you elaborate on the "moveable feast" analogy? – Karoh Sep 15 '22 at 21:04
  • There's a lot there and things change over time (especially since that answer is at this point almost exactly 8 years old). – Kevin Teljeur Sep 20 '22 at 17:18
72
app.get('/:var(bla|blabla)?', todo)

:var sets the req.param that you don't use. it's only used in this case to set the regex.

(bla|blabla) sets the regex to match, so it matches the strings bla and blablah.

? makes the entire regex optional, so it matches / as well.

Jonathan Ong
  • 19,927
  • 17
  • 79
  • 118
  • 1
    `/bla(bla)?` also works, but any parameters after does not populate properly (ie `/bla(bla)?/:value` does not populate `req.params.value`). Anyone know why? – joscarsson Jan 21 '15 at 21:15
  • If your using express you can get it with `req.params.var` but you need to make sure you have `req` passed to the function – Matt The Ninja Sep 07 '15 at 13:10
64

You can actually pass in an array of paths, just like you mentioned, and it works great:

var a = ['/', '/blabla', '/blablablabla'];
app.get(a, todo);
nbro
  • 15,395
  • 32
  • 113
  • 196
alex
  • 701
  • 5
  • 5
49

Just to elaborate on Kevin's answer, this is from the 4.x docs:

The path for which the middleware function is invoked; can be any of:

  • A string representing a path.
  • A path pattern.
  • A regular expression pattern to match paths.
  • An array of combinations of any of the above.

They have some examples, including:

This will match paths starting with /abcd, /xyza, /lmn, and /pqr:

app.use(['/abcd', '/xyza', /\/lmn|\/pqr/], function (req, res, next) {
  next();
});
Community
  • 1
  • 1
c24w
  • 7,421
  • 7
  • 39
  • 47
21

I went for a:

['path', 'altPath'].forEach(function(path) {
  app.get(path, function(req, res) { etc. });
});
Augustin Riedinger
  • 20,909
  • 29
  • 133
  • 206