79

I'm not very good with regular expressions, so I want to make sure I'm doing this correctly. Let's say I have two very similar routes, /discussion/:slug/ and /page/:slug/. I want to create a route that matches both these pages.

app.get('/[discussion|page]/:slug', function(req, res, next) {
  ...enter code here...
})

Is this the correct way to do it? Right now I'm just creating two separate routes.

someFunction = function(req, res, next) {..}
app.get('/discussion/:slug', someFunction)
app.get('/page/:slug', someFunction)
Greg
  • 481
  • 1
  • 5
  • 21
Jonathan Ong
  • 19,927
  • 17
  • 79
  • 118
  • 4
    Are you confident on the `[]` brackets for alternation? That'd be the first time I've seen them used in this way. (Parens `()` are more common in more tools -- I just don't know your specific tool.) – sarnold Jun 01 '12 at 22:23
  • 1
    whoops, typo. but i'm trying to find examples for express and i can't find any (or I don't know the terms to search). – Jonathan Ong Jun 01 '12 at 22:25
  • just make 'someFunction' the same exact function, this is way easier to do, maybe you already have done this – Alexander Mills Jul 03 '15 at 04:06
  • In such a case app.get(['/discussion/:slug', /page/:slug'], function(req, res, next) { ...enter code here... }) is also an option. – Max May 22 '19 at 06:59

2 Answers2

128

app.get('/:type(discussion|page)/:id', ...) works

Jonathan Ong
  • 19,927
  • 17
  • 79
  • 118
  • 9
    I think the key point of this is that you can assign the request parameter to the regex by placing it in "( )" after the param name IE: `:type()` will set `req.params.type` to the matched string You can't put the regex before the variable. – duality Aug 21 '15 at 00:05
  • 2
    This syntax looks great, but doesn't seem to be documented at https://expressjs.com/en/guide/routing.html at all :-( – rjmunro Oct 05 '16 at 08:22
  • 7
    @rjmunro It's documented in the `path-to-regexp` module, which Express uses. (This is mentioned in the Express docs but, yeah, it's easy to overlook.) See https://github.com/pillarjs/path-to-regexp – broofa Oct 10 '16 at 23:43
  • Thanks, it is works for me. However it seems `case sensitive` set to `false` by default. Can I set it to true? This seems to be the official docs [path-to-regexp](https://github.com/pillarjs/path-to-regexp#usage) – bcjohn Apr 16 '20 at 02:30
71

You should use a literal javascript regular expression object, not a string, and @sarnold is correct that you want parens for alternation. Square brackets are for character classes.

const express = require("express");
const app = express.createServer();
app.get(/^\/(discussion|page)\/(.+)/, function (req, res, next) {
  res.write(req.params[0]); //This has "discussion" or "page"
  res.write(req.params[1]); //This has the slug
  res.end();
});

app.listen(9060);

The (.+) means a slug of at least 1 character must be present or this route will not match. Use (.*) if you want it to match an empty slug as well.

Peter Lyons
  • 142,938
  • 30
  • 279
  • 274
  • Is there a way to use this without regex and as a string? I prefer keyword params instead of a list. – Jonathan Ong Jul 03 '12 at 02:10
  • 1
    AFAIK there is no way to use a string with named params if you need the sophisticated matching abilities of regular expressions. TJ says something to this effect in the express documentation. I believe it is ultimately a limitation of javascript regular expression objects. – Peter Lyons Jul 03 '12 at 02:28
  • 3
    you can do this `app.get(new RegExp('(your|string)\/here'), function…` – Misha Reyzlin Oct 23 '12 at 22:13
  • 5
    Your regexp isn't anchored at the start of the url. Does express explicitly anchor or should the regexp be /\/(discussion|pa... – user239558 Nov 15 '13 at 12:11
  • 1
    It should be `/^\/(discussion|page)\/(.+)/` as suggested by the user above. I've suggested an edit. –  Mar 31 '17 at 02:35
  • Don't forget to terminate the expression too. e.g `/^\/(your|string)+$/` – hiddensunset4 Jan 31 '18 at 04:57
  • Yeah, without `\/` in the beginning there's some weird behavior. Should always be there. – seeker_of_bacon Sep 30 '18 at 18:07