240

I'm using express + node.js and I have a req object, the request in the browser is /account but when I log req.path I get '/' --- not '/account'.

  //auth required or redirect
  app.use('/account', function(req, res, next) {
    console.log(req.path);
    if ( !req.session.user ) {
      res.redirect('/login?ref='+req.path);
    } else {
      next();
    }
  });

req.path is / when it should be /account ??

chovy
  • 72,281
  • 52
  • 227
  • 295
  • 4
    `TypeError: Cannot read property 'path' of undefined` – chovy Sep 21 '12 at 08:24
  • req.route.path is correct and documented [here](http://expressjs.com/api.html#req.route). Which version of express are you using? – zemirco Sep 21 '12 at 17:31
  • I'm having the same issue. `req.route` is undefined. Im using express 3.4.4. What can cause route to be undefined? – davidpfahler Nov 12 '13 at 20:50
  • @vinayr req.route.path still gives me /create instead of /quizzes/create, which is the whole URL – Sandip Subedi Apr 15 '17 at 20:02
  • This is intended behavior. And you should embrace it. Your handler should not care about the full path, but only about the 'local' part of the path. That's the part after the path it was mounted on. This makes the handler function more easy to reuse in other contexts. – Stijn de Witt Dec 09 '17 at 18:28
  • There's now a way to do this in later version. See my answer below. – c1moore Oct 02 '19 at 15:12
  • It's undefined inside middleware handlers only. Inside route handlers there's a route for sure. – Omar Dulaimi May 28 '22 at 04:51
  • As mentioned by @c1moore it's not possible to get complete path using req object. Although if you patch express then you can record this info in req. I ended up making this package [px5](https://www.npmjs.com/package/px5) to do it. – TubbyStubby Feb 05 '23 at 21:07

11 Answers11

329

After having a bit of a play myself, you should use:

console.log(req.originalUrl)

Emech
  • 611
  • 1
  • 4
  • 16
Menztrual
  • 40,867
  • 12
  • 57
  • 70
  • 4
    I think its got something to do with the positioning of middleware, but you are correct, it doesn't make sense. – Menztrual Sep 22 '12 at 05:55
  • 1
    It's definitely the middleware. This happens with additional routers in Express 4 as well. When either is mounted off of a given path, inside of itself it gets to pretend that it's off of the root. That's nice for isolation, but tricky when you don't know how to get what the original full value was. Thanks for posting this! – juanpaco Apr 23 '15 at 12:31
  • 3
    Anyone getting here on 4.0, req.url is designed to be mutable by middleware for re-routing purposes, and req.path could be missing mounting points depending upon where it's called. http://expressjs.com/en/api.html#req.originalUrl – Christian Davis Jul 21 '17 at 19:06
  • 3
    If you don't want the query string included: `const path = req.originalUrl.replace(/\?.*$/, '');` – Adam Reis Feb 05 '19 at 04:03
  • 4
    Warning: This is a misleading answer, based on the OP question. This will also return the query string (e.g. ?a=b&c=5) if it was present. See http://expressjs.com/en/api.html#req.originalUrl – Ciabaros May 29 '19 at 14:32
  • 1
    This simply does not give a path but a full url... Also useful but not what OP asked. To do what OP wants, see [this answer](https://stackoverflow.com/a/56380963/286685). – Stijn de Witt May 03 '20 at 13:37
  • I don't think `req.originalUrl` is a good solution in this scenario. In Firebase Function, you'll get `/project-id/us-central1/app/account` instead of `/account`. You may also get an obsolete URL, which has been permanently redirected. – Antonio Ooi Jun 12 '20 at 08:58
99

Here is an example expanded from the documentation, which nicely wraps all you need to know about accessing the paths/URLs in all cases with express:

app.use('/admin', function (req, res, next) { // GET 'http://www.example.com/admin/new?a=b'
  console.dir(req.originalUrl) // '/admin/new?a=b' (WARNING: beware query string)
  console.dir(req.baseUrl) // '/admin'
  console.dir(req.path) // '/new'
  console.dir(req.baseUrl + req.path) // '/admin/new' (full path without query string)
  next()
})

Based on: https://expressjs.com/en/api.html#req.originalUrl

Conclusion: As c1moore's answer states, use:

var fullPath = req.baseUrl + req.path;
Ciabaros
  • 1,984
  • 13
  • 15
83

In some cases you should use:

req.path

This gives you the path, instead of the complete requested URL. For example, if you are only interested in which page the user requested and not all kinds of parameters the url:

/myurl.htm?allkinds&ofparameters=true

req.path will give you:

/myurl.html
DivZero
  • 2,438
  • 2
  • 24
  • 23
  • 1
    Be careful that if you're doing checks against this URL to also include a check for a trailing slash if it's valid in your app. (i.e. checking for `/demo` should also potentially check for `/demo/`). – Vinay Jun 02 '16 at 00:20
  • If you don't want the query string included: const path = req.originalUrl.replace(/\?.*$/, ''); – Adam Reis Feb 05 '19 at 04:03
  • `req.path` is the shorthand of `url.parse(req.url).pathname` and this should be the accepted answer – sertsedat Mar 10 '20 at 17:00
  • 3
    @sertsedat Incorrect. `req.path` gives you the relative path to where your app is mounted. If it is mounted at the root than this is correct, but for a path `/my/path`, within an app mounted at `/my`, `req.url` will give `/path`. – Stijn de Witt May 03 '20 at 13:32
17

This can produce different results when calling directly in base module i.e. main file (e.g. index.js or app.js) vs calling from inside module via app.use() middleware i.e. route file (e.g. routes/users.js).

API call:
http://localhost:8000/api/users/profile/123/summary?view=grid&leng=en

We'll be comparing our outputs against above API call


First, we'll see the result from innner module:

  1. We'll be placing our user module inside routes directory, with one route i.e. /profile/:id/:details

    routes/users.js file

    const router = (require('express')).Router();
    
    router.get('/profile/:id/:details', (req, res) => {
    
        console.log(req.protocol);        // http or https
        console.log(req.hostname);        // only hostname without port
        console.log(req.headers.host);    // hostname with port number (if any); same result with req.header('host')
        console.log(req.route.path);      // exact defined route
        console.log(req.baseUrl);         // base path or group prefix
        console.log(req.path);            // relative path except query params
        console.log(req.url);             // relative path with query|search params
        console.log(req.originalUrl);     // baseURL + url
    
        // Full URL
        console.log(`${req.protocol}://${req.header('host')}${req.originalUrl}`);
    
        res.sendStatus(200);
    
    });
    
    module.exports = router;
    
  2. Now we'll import this user module in main module of the application and add /api/users as base path for user module using app.use() middleware

    index.js file

    const app = (require('express'))();
    
    const users = require('./routes/users');
    app.use('/api/users', users);
    
    const server = require('http').createServer(app);
    server.listen(8000, () => console.log('server listening'));
    

Output

[req.protocol] ............. http
[req.hostname] .......... localhost
[req.headers.host] ..... localhost:8000
[req.route.path] .......... /profile/:id/:details
[req.baseUrl] .............. /api/users
[req.path] ................... /profile/123/summary
[req.url] ...................... /profile/123/summary?view=grid&leng=en
[req.originalUrl] .......... /api/users/profile/123/summary?view=grid&leng=en

Full URL:
http://localhost:8000/api/users/profile/123/summary?view=grid&leng=en


Now, we'll see result if we add routes directly in main module:

  1. We'll define our route right in the main module (i.e. app.js or index.js) and concatenate base path /app/users with route path instead of using middleware. So route will become /api/users/profile/:id/:details

    index.js file

    const app = (require('express'))();
    
    app.get('/api/users/profile/:id/:details', (req, res) => {
    
        console.log(req.protocol);        // http or https
        console.log(req.hostname);        // only hostname without port
        console.log(req.headers.host);    // hostname with port number (if any); same result with req.header('host')
        console.log(req.route.path);      // exact defined route
        console.log(req.baseUrl);         // base path or group prefix
        console.log(req.path);            // relative path except query params
        console.log(req.url);             // relative path with query|search params
        console.log(req.originalUrl);     // baseURL + url
    
        // Full URL
        console.log(`${req.protocol}://${req.header('host')}${req.originalUrl}`);
    
        res.sendStatus(200);
    
    });
    
    const server = require('http').createServer(app);
    server.listen(8000, () => console.log('server listening'));
    

Output

[req.protocol] ............. http
[req.hostname] .......... localhost
[req.headers.host] ..... localhost:8000
[req.route.path] .......... /api/users/profile/:id/:details
[req.baseUrl] ..............
[req.path] ................... /api/users/profile/123/summary
[req.url] ...................... /api/users/profile/123/summary?view=grid&leng=en
[req.originalUrl] .......... /api/users/profile/123/summary?view=grid&leng=en

Full URL:
http://localhost:8000/api/users/profile/123/summary?view=grid&leng=en

We can clearly see in above output that the only difference is of baseUrl which is empty string here. So, the originalUrl also changes & looks same as the url

TalESid
  • 2,304
  • 1
  • 20
  • 41
16

UPDATE 8 YEARS LATER:

req.path was already doing exactly same thing that I mentioned here. I don't remember how this answer solved issue and accepted as a correct answer but currently it's not a valid answer. Please ignore this answer. Thanks @mhodges for mentioning this.

Original answer:

If you want to really get only "path" without querystring, you can use url library to parse and get only path part of url.

var url = require('url');

//auth required or redirect
app.use('/account', function(req, res, next) {
    var path = url.parse(req.url).pathname;
    if ( !req.session.user ) {
      res.redirect('/login?ref='+path);
    } else {
      next();
    }
});
Murat Çorlu
  • 8,207
  • 5
  • 53
  • 78
  • this exactly is what i want. Use it with ```req.query.ref``` if login successful – Ryan Wu Nov 19 '13 at 16:14
  • This works nicely with universal code since it conforms to [Location](https://developer.mozilla.org/en-US/docs/Web/API/Location) spec. Less things to remember and easier to unit test across client and server. – cchamberlain Oct 11 '16 at 20:13
  • 1
    `req.path` is just an alias for `url.parse(req.url).pathname` – mhodges Apr 20 '20 at 22:43
  • 1
    @mhodges Wow, that looks completely true. This is a 8 years old answer and I have no clue how we thought that answer solves the issue. Thanks for mentioning. I'll update answer or maybe just delete it. – Murat Çorlu Oct 25 '21 at 07:40
13
//auth required or redirect
app.use('/account', function(req, res, next) {
  console.log(req.path);
  if ( !req.session.user ) {
    res.redirect('/login?ref='+req.path);
  } else {
    next();
  }
});

req.path is / when it should be /account ??

The reason for this is that Express subtracts the path your handler function is mounted on, which is '/account' in this case.

Why do they do this?

Because it makes it easier to reuse the handler function. You can make a handler function that does different things for req.path === '/' and req.path === '/goodbye' for example:

function sendGreeting(req, res, next) {
  res.send(req.path == '/goodbye' ? 'Farewell!' : 'Hello there!')
}

Then you can mount it to multiple endpoints:

app.use('/world', sendGreeting)
app.use('/aliens', sendGreeting)

Giving:

/world           ==>  Hello there!
/world/goodbye   ==>  Farewell!
/aliens          ==>  Hello there!
/aliens/goodbye  ==>  Farewell!
Stijn de Witt
  • 40,192
  • 13
  • 79
  • 80
  • I'm amazed this answer isn't voted up much more, since it clearly answers the question and explains the behaviour (unlike all the higher-voted answers). Thanks! – Mark Longair Nov 02 '22 at 08:28
12

It should be:

req.url

express 3.1.x

Jürgen Paul
  • 14,299
  • 26
  • 93
  • 133
  • 1
    req.url is not a native Express property, it is inherited from Node’s http module: https://expressjs.com/en/api.html#req.originalUrl – Megagator Feb 21 '20 at 17:26
11

For version 4.x you can now use the req.baseUrl in addition to req.path to get the full path. For example, the OP would now do something like:

//auth required or redirect
app.use('/account', function(req, res, next) {
  console.log(req.baseUrl + req.path);  // => /account

  if(!req.session.user) {
    res.redirect('/login?ref=' + encodeURIComponent(req.baseUrl + req.path));  // => /login?ref=%2Faccount
  } else {
    next();
  }
});
c1moore
  • 1,827
  • 17
  • 27
6

req.route.path is working for me

var pool = require('../db');

module.exports.get_plants = function(req, res) {
    // to run a query we can acquire a client from the pool,
    // run a query on the client, and then return the client to the pool
    pool.connect(function(err, client, done) {
        if (err) {
            return console.error('error fetching client from pool', err);
        }
        client.query('SELECT * FROM plants', function(err, result) {
            //call `done()` to release the client back to the pool
            done();
            if (err) {
                return console.error('error running query', err);
            }
            console.log('A call to route: %s', req.route.path + '\nRequest type: ' + req.method.toLowerCase());
            res.json(result);
        });
    });
};

after executing I see the following in the console and I get perfect result in my browser.

Express server listening on port 3000 in development mode
A call to route: /plants
Request type: get
Bahman.A
  • 1,166
  • 4
  • 18
  • 33
1

When using a middleware in express, your request object has several properties you can use to get the correct path:

  • req.baseUrl: /api/account
  • req.originalUrl: /api/account
  • req._parsedUrl.path: /account
  • req._parsedUrl.pathname: /account
  • req._parsedUrl.href: /account
  • req._parsedUrl._raw: /account

PLEASE NOTE: This applies to middlewares

mrbridge
  • 11
  • 2
0

For those getting undefined from req.route.path that is correct.

Inside route handler, there's a route. Inside middleware handlers, there's no route.

Omar Dulaimi
  • 846
  • 10
  • 30