[node.js] How to get all registered routes in Express?

I have a web application built using Node.js and Express. Now I would like to list all registered routes with their appropriate methods.

E.g., if I have executed

app.get('/', function (...) { ... });
app.get('/foo/:id', function (...) { ... });
app.post('/foo/:id', function (...) { ... });

I would like to retrieve an object (or something equivalent to that) such as:

{
  get: [ '/', '/foo/:id' ],
  post: [ '/foo/:id' ]
}

Is this possible, and if so, how?


UPDATE: Meanwhile, I have created an npm package called get-routes that extracts the routes from a given application, which solves this issue. Currently, only Express 4.x is supported, but I guess for now this is fine. Just FYI.

This question is related to node.js express

The answer is


app._router.stack.forEach(function(r){
  if (r.route && r.route.path){
    console.log(r.route.path)
  }
})

On Express 3.5.x, I add this before starting the app to print the routes on my terminal :

var routes = app.routes;
for (var verb in routes){
    if (routes.hasOwnProperty(verb)) {
      routes[verb].forEach(function(route){
        console.log(verb + " : "+route['path']);
      });
    }
}

Maybe it can help...


json output

function availableRoutes() {
  return app._router.stack
    .filter(r => r.route)
    .map(r => {
      return {
        method: Object.keys(r.route.methods)[0].toUpperCase(),
        path: r.route.path
      };
    });
}

console.log(JSON.stringify(availableRoutes(), null, 2));

looks like this:

[
  {
    "method": "GET",
    "path": "/api/todos"
  },
  {
    "method": "POST",
    "path": "/api/todos"
  },
  {
    "method": "PUT",
    "path": "/api/todos/:id"
  },
  {
    "method": "DELETE",
    "path": "/api/todos/:id"
  }
]

string output

function availableRoutesString() {
  return app._router.stack
    .filter(r => r.route)
    .map(r => Object.keys(r.route.methods)[0].toUpperCase().padEnd(7) + r.route.path)
    .join("\n  ")
}

console.log(availableRoutesString());

looks like this:

GET    /api/todos  
POST   /api/todos  
PUT    /api/todos/:id  
DELETE /api/todos/:id

these are based on @corvid's answer

hope this helps


I published a package that prints all middleware as well as routes, really useful when trying to audit an express application. You mount the package as middleware, so it even prints out itself:

https://github.com/ErisDS/middleware-stack-printer

It prints a kind of tree like:

- middleware 1
- middleware 2
- Route /thing/
- - middleware 3
- - controller (HTTP VERB)  

Hacky copy/paste answer courtesy of Doug Wilson on the express github issues. Dirty but works like a charm.

function print (path, layer) {
  if (layer.route) {
    layer.route.stack.forEach(print.bind(null, path.concat(split(layer.route.path))))
  } else if (layer.name === 'router' && layer.handle.stack) {
    layer.handle.stack.forEach(print.bind(null, path.concat(split(layer.regexp))))
  } else if (layer.method) {
    console.log('%s /%s',
      layer.method.toUpperCase(),
      path.concat(split(layer.regexp)).filter(Boolean).join('/'))
  }
}

function split (thing) {
  if (typeof thing === 'string') {
    return thing.split('/')
  } else if (thing.fast_slash) {
    return ''
  } else {
    var match = thing.toString()
      .replace('\\/?', '')
      .replace('(?=\\/|$)', '$')
      .match(/^\/\^((?:\\[.*+?^${}()|[\]\\\/]|[^.*+?^${}()|[\]\\\/])*)\$\//)
    return match
      ? match[1].replace(/\\(.)/g, '$1').split('/')
      : '<complex:' + thing.toString() + '>'
  }
}

app._router.stack.forEach(print.bind(null, []))

Produces

screengrab


https://www.npmjs.com/package/express-list-endpoints works pretty well.

Example

Usage:

const all_routes = require('express-list-endpoints');
console.log(all_routes(app));

Output:

[ { path: '*', methods: [ 'OPTIONS' ] },
  { path: '/', methods: [ 'GET' ] },
  { path: '/sessions', methods: [ 'POST' ] },
  { path: '/sessions', methods: [ 'DELETE' ] },
  { path: '/users', methods: [ 'GET' ] },
  { path: '/users', methods: [ 'POST' ] } ]

Need some adjusts but should work for Express v4. Including those routes added with .use().

function listRoutes(routes, stack, parent){

  parent = parent || '';
  if(stack){
    stack.forEach(function(r){
      if (r.route && r.route.path){
        var method = '';

        for(method in r.route.methods){
          if(r.route.methods[method]){
            routes.push({method: method.toUpperCase(), path: parent + r.route.path});
          }
        }       

      } else if (r.handle && r.handle.name == 'router') {
        const routerName = r.regexp.source.replace("^\\","").replace("\\/?(?=\\/|$)","");
        return listRoutes(routes, r.handle.stack, parent + routerName);
      }
    });
    return routes;
  } else {
    return listRoutes([], app._router.stack);
  }
}

//Usage on app.js
const routes = listRoutes(); //array: ["method: path", "..."]

edit: code improvements


In express 4.*

//Obtiene las rutas declaradas de la API
    let listPathRoutes: any[] = [];
    let rutasRouter = _.filter(application._router.stack, rutaTmp => rutaTmp.name === 'router');
    rutasRouter.forEach((pathRoute: any) => {
        let pathPrincipal = pathRoute.regexp.toString();
        pathPrincipal = pathPrincipal.replace('/^\\','');
        pathPrincipal = pathPrincipal.replace('?(?=\\/|$)/i','');
        pathPrincipal = pathPrincipal.replace(/\\\//g,'/');
        let routesTemp = _.filter(pathRoute.handle.stack, rutasTmp => rutasTmp.route !== undefined);
        routesTemp.forEach((route: any) => {
            let pathRuta = `${pathPrincipal.replace(/\/\//g,'')}${route.route.path}`;
            let ruta = {
                path: pathRuta.replace('//','/'),
                methods: route.route.methods
            }
            listPathRoutes.push(ruta);
        });
    });console.log(listPathRoutes)

DEBUG=express:* node index.js

If you run your app with the above command, it will launch your app with DEBUG module and gives routes, plus all the middleware functions that are in use.

You can refer: ExpressJS - Debugging and debug.


Here's a little thing I use just to get the registered paths in express 4.x

app._router.stack          // registered routes
  .filter(r => r.route)    // take out all the middleware
  .map(r => r.route.path)  // get all the paths

This gets routes registered directly on the app (via app.VERB) and routes that are registered as router middleware (via app.use). Express 4.11.0

//////////////
app.get("/foo", function(req,res){
    res.send('foo');
});

//////////////
var router = express.Router();

router.get("/bar", function(req,res,next){
    res.send('bar');
});

app.use("/",router);


//////////////
var route, routes = [];

app._router.stack.forEach(function(middleware){
    if(middleware.route){ // routes registered directly on the app
        routes.push(middleware.route);
    } else if(middleware.name === 'router'){ // router middleware 
        middleware.handle.stack.forEach(function(handler){
            route = handler.route;
            route && routes.push(route);
        });
    }
});

// routes:
// {path: "/foo", methods: {get: true}}
// {path: "/bar", methods: {get: true}}

So I was looking at all the answers.. didn't like most.. took some from a few.. made this:

const resolveRoutes = (stack) => {
  return stack.map(function (layer) {
    if (layer.route && layer.route.path.isString()) {
      let methods = Object.keys(layer.route.methods);
      if (methods.length > 20)
        methods = ["ALL"];

      return {methods: methods, path: layer.route.path};
    }

    if (layer.name === 'router')  // router middleware
      return resolveRoutes(layer.handle.stack);

  }).filter(route => route);
};

const routes = resolveRoutes(express._router.stack);
const printRoute = (route) => {
  if (Array.isArray(route))
    return route.forEach(route => printRoute(route));

  console.log(JSON.stringify(route.methods) + " " + route.path);
};

printRoute(routes);

not the prettiest.. but nested, and does the trick

also note the 20 there... I just assume there will not be a normal route with 20 methods.. so I deduce it is all..


A function to log all routes in express 4 (can be easily tweaked for v3~)

function space(x) {
    var res = '';
    while(x--) res += ' ';
    return res;
}

function listRoutes(){
    for (var i = 0; i < arguments.length;  i++) {
        if(arguments[i].stack instanceof Array){
            console.log('');
            arguments[i].stack.forEach(function(a){
                var route = a.route;
                if(route){
                    route.stack.forEach(function(r){
                        var method = r.method.toUpperCase();
                        console.log(method,space(8 - method.length),route.path);
                    })
                }
            });
        }
    }
}

listRoutes(router, routerAuth, routerHTML);

Logs output:

GET       /isAlive
POST      /test/email
POST      /user/verify

PUT       /login
POST      /login
GET       /player
PUT       /player
GET       /player/:id
GET       /players
GET       /system
POST      /user
GET       /user
PUT       /user
DELETE    /user

GET       /
GET       /login

Made this into a NPM https://www.npmjs.com/package/express-list-routes


I have adapted an old post that is no longer online for my needs. I've used express.Router() and registered my routes like this:

var questionsRoute = require('./BE/routes/questions');
app.use('/api/questions', questionsRoute);

I renamed the document.js file in apiTable.js and adapted it like this:

module.exports =  function (baseUrl, routes) {
    var Table = require('cli-table');
    var table = new Table({ head: ["", "Path"] });
    console.log('\nAPI for ' + baseUrl);
    console.log('\n********************************************');

    for (var key in routes) {
        if (routes.hasOwnProperty(key)) {
            var val = routes[key];
            if(val.route) {
                val = val.route;
                var _o = {};
                _o[val.stack[0].method]  = [baseUrl + val.path];    
                table.push(_o);
            }       
        }
    }

    console.log(table.toString());
    return table;
};

then i call it in my server.js like this:

var server = app.listen(process.env.PORT || 5000, function () {
    require('./BE/utils/apiTable')('/api/questions', questionsRoute.stack);
});

The result looks like this:

Result example

It's just an example but might be of use.. i hope..


Here is a one-line function to pretty-print the routes in an Express app:

const getAppRoutes = (app) => app._router.stack.reduce(
  (acc, val) => acc.concat(
    val.route ? [val.route.path] :
      val.name === "router" ? val.handle.stack.filter(
        x => x.route).map(
          x => val.regexp.toString().match(/\/[a-z]+/)[0] + (
            x.route.path === '/' ? '' : x.route.path)) : []) , []).sort();

route details are listing route for "express": "4.x.x",

import {
  Router
} from 'express';
var router = Router();

router.get("/routes", (req, res, next) => {
  var routes = [];
  var i = 0;
  router.stack.forEach(function (r) {
    if (r.route && r.route.path) {
      r.route.stack.forEach(function (type) {
        var method = type.method.toUpperCase();
        routes[i++] = {
          no:i,
          method: method.toUpperCase(),
          path: r.route.path
        };
      })
    }
  })

  res.send('<h1>List of routes.</h1>' + JSON.stringify(routes));
});

SIMPLE OUTPUT OF CODE

List of routes.

[
{"no":1,"method":"POST","path":"/admin"},
{"no":2,"method":"GET","path":"/"},
{"no":3,"method":"GET","path":"/routes"},
{"no":4,"method":"POST","path":"/student/:studentId/course/:courseId/topic/:topicId/task/:taskId/item"},
{"no":5,"method":"GET","path":"/student/:studentId/course/:courseId/topic/:topicId/task/:taskId/item"},
{"no":6,"method":"PUT","path":"/student/:studentId/course/:courseId/topic/:topicId/task/:taskId/item/:itemId"},
{"no":7,"method":"DELETE","path":"/student/:studentId/course/:courseId/topic/:topicId/task/:taskId/item/:itemId"}
]

This worked for me

let routes = []
app._router.stack.forEach(function (middleware) {
    if(middleware.route) {
        routes.push(Object.keys(middleware.route.methods) + " -> " + middleware.route.path);
    }
});

console.log(JSON.stringify(routes, null, 4));

O/P:

[
    "get -> /posts/:id",
    "post -> /posts",
    "patch -> /posts"
]

Slightly updated and more functional approach to @prranay's answer:

const routes = app._router.stack
    .filter((middleware) => middleware.route)
    .map((middleware) => `${Object.keys(middleware.route.methods).join(', ')} -> ${middleware.route.path}`)

console.log(JSON.stringify(routes, null, 4));

Just use this npm package, it will give the web-output as well as terminal output in nice formatted table view.

enter image description here

https://www.npmjs.com/package/express-routes-catalogue


You can implement a /get-all-routes API:

const express = require("express");
const app = express();

app.get("/get-all-routes", (req, res) => {  
  let get = app._router.stack.filter(r => r.route && r.route.methods.get).map(r => r.route.path);
  let post = app._router.stack.filter(r => r.route && r.route.methods.post).map(r => r.route.path);
  res.send({ get: get, post: post });
});

const listener = app.listen(process.env.PORT, () => {
  console.log("Your app is listening on port " + listener.address().port);
});

Here is a demo: https://glitch.com/edit/#!/get-all-routes-in-nodejs


Initialize express router

let router = require('express').Router();
router.get('/', function (req, res) {
    res.json({
        status: `API Its Working`,
        route: router.stack.filter(r => r.route)
           .map(r=> { return {"path":r.route.path, 
 "methods":r.route.methods}}),
        message: 'Welcome to my crafted with love!',
      });
   });   

Import user controller

var userController = require('./controller/userController');

User routes

router.route('/users')
   .get(userController.index)
   .post(userController.new);
router.route('/users/:user_id')
   .get(userController.view)
   .patch(userController.update)
   .put(userController.update)
   .delete(userController.delete);

Export API routes

module.exports = router;

Output

{"status":"API Its Working, APP Route","route": 
[{"path":"/","methods":{"get":true}}, 
{"path":"/users","methods":{"get":true,"post":true}}, 
{"path":"/users/:user_id","methods": ....}

I was inspired by Labithiotis's express-list-routes, but I wanted an overview of all my routes and brute urls in one go, and not specify a router, and figure out the prefix each time. Something I came up with was to simply replace the app.use function with my own function which stores the baseUrl and given router. From there I can print any table of all my routes.

NOTE this works for me because I declare my routes in a specific routes file (function) which gets passed in the app object, like this:

// index.js
[...]
var app = Express();
require(./config/routes)(app);

// ./config/routes.js
module.exports = function(app) {
    // Some static routes
    app.use('/users', [middleware], UsersRouter);
    app.use('/users/:user_id/items', [middleware], ItemsRouter);
    app.use('/otherResource', [middleware], OtherResourceRouter);
}

This allows me to pass in another 'app' object with a fake use function, and I can get ALL the routes. This works for me (removed some error checking for clarity, but still works for the example):

// In printRoutes.js (or a gulp task, or whatever)
var Express = require('express')
  , app     = Express()
  , _       = require('lodash')

// Global array to store all relevant args of calls to app.use
var APP_USED = []

// Replace the `use` function to store the routers and the urls they operate on
app.use = function() {
  var urlBase = arguments[0];

  // Find the router in the args list
  _.forEach(arguments, function(arg) {
    if (arg.name == 'router') {
      APP_USED.push({
        urlBase: urlBase,
        router: arg
      });
    }
  });
};

// Let the routes function run with the stubbed app object.
require('./config/routes')(app);

// GRAB all the routes from our saved routers:
_.each(APP_USED, function(used) {
  // On each route of the router
  _.each(used.router.stack, function(stackElement) {
    if (stackElement.route) {
      var path = stackElement.route.path;
      var method = stackElement.route.stack[0].method.toUpperCase();

      // Do whatever you want with the data. I like to make a nice table :)
      console.log(method + " -> " + used.urlBase + path);
    }
  });
});

This full example (with some basic CRUD routers) was just tested and printed out:

GET -> /users/users
GET -> /users/users/:user_id
POST -> /users/users
DELETE -> /users/users/:user_id
GET -> /users/:user_id/items/
GET -> /users/:user_id/items/:item_id
PUT -> /users/:user_id/items/:item_id
POST -> /users/:user_id/items/
DELETE -> /users/:user_id/items/:item_id
GET -> /otherResource/
GET -> /otherResource/:other_resource_id
POST -> /otherResource/
DELETE -> /otherResource/:other_resource_id

Using cli-table I got something like this:

+--------------------------------+
¦        ¦ => Users              ¦
+--------+-----------------------¦
¦ GET    ¦ /users/users          ¦
+--------+-----------------------¦
¦ GET    ¦ /users/users/:user_id ¦
+--------+-----------------------¦
¦ POST   ¦ /users/users          ¦
+--------+-----------------------¦
¦ DELETE ¦ /users/users/:user_id ¦
+--------------------------------+
+-----------------------------------------+
¦        ¦ => Items                       ¦
+--------+--------------------------------¦
¦ GET    ¦ /users/:user_id/items/         ¦
+--------+--------------------------------¦
¦ GET    ¦ /users/:user_id/items/:item_id ¦
+--------+--------------------------------¦
¦ PUT    ¦ /users/:user_id/items/:item_id ¦
+--------+--------------------------------¦
¦ POST   ¦ /users/:user_id/items/         ¦
+--------+--------------------------------¦
¦ DELETE ¦ /users/:user_id/items/:item_id ¦
+-----------------------------------------+
+--------------------------------------------+
¦        ¦ => OtherResources                 ¦
+--------+-----------------------------------¦
¦ GET    ¦ /otherResource/                   ¦
+--------+-----------------------------------¦
¦ GET    ¦ /otherResource/:other_resource_id ¦
+--------+-----------------------------------¦
¦ POST   ¦ /otherResource/                   ¦
+--------+-----------------------------------¦
¦ DELETE ¦ /otherResource/:other_resource_id ¦
+--------------------------------------------+

Which kicks ass.


This one worked for me

// Express 4.x
function getRoutes(stacks: any, routes: { path: string; method: string }[] = [], prefix: string = ''): { path: string; method: string }[] {
  for (const stack of stacks) {
    if (stack.route) {
      routes.push({ path: `${prefix}${stack.route.path}`, method: stack.route.stack[0].method });
    }
    if (stack && stack.handle && stack.handle.stack) {
      let stackPrefix = stack.regexp.source.match(/\/[A-Za-z0-9_-]+/g);

      if (stackPrefix) {
        stackPrefix = prefix + stackPrefix.join('');
      }

      routes.concat(getRoutes(stack.handle.stack, routes, stackPrefix));
    }
  }
  return routes;
}

Express 4

Given an Express 4 configuration with endpoints and nested routers

const express = require('express')
const app = express()
const router = express.Router()

app.get(...)
app.post(...)

router.use(...)
router.get(...)
router.post(...)

app.use(router)

Expanding the @caleb answer it is possible to obtain all routes recursively and sorted.

getRoutes(app._router && app._router.stack)
// =>
// [
//     [ 'GET', '/'], 
//     [ 'POST', '/auth'],
//     ...
// ]

/**
* Converts Express 4 app routes to an array representation suitable for easy parsing.
* @arg {Array} stack An Express 4 application middleware list.
* @returns {Array} An array representation of the routes in the form [ [ 'GET', '/path' ], ... ].
*/
function getRoutes(stack) {
        const routes = (stack || [])
                // We are interested only in endpoints and router middleware.
                .filter(it => it.route || it.name === 'router')
                // The magic recursive conversion.
                .reduce((result, it) => {
                        if (! it.route) {
                                // We are handling a router middleware.
                                const stack = it.handle.stack
                                const routes = getRoutes(stack)

                                return result.concat(routes)
                        }

                        // We are handling an endpoint.
                        const methods = it.route.methods
                        const path = it.route.path

                        const routes = Object
                                .keys(methods)
                                .map(m => [ m.toUpperCase(), path ])

                        return result.concat(routes)
                }, [])
                // We sort the data structure by route path.
                .sort((prev, next) => {
                        const [ prevMethod, prevPath ] = prev
                        const [ nextMethod, nextPath ] = next

                        if (prevPath < nextPath) {
                                return -1
                        }

                        if (prevPath > nextPath) {
                                return 1
                        }

                        return 0
                })

        return routes
}

For basic string output.

infoAboutRoutes(app)

Console output

/**
* Converts Express 4 app routes to a string representation suitable for console output.
* @arg {Object} app An Express 4 application
* @returns {string} A string representation of the routes.
*/
function infoAboutRoutes(app) {
        const entryPoint = app._router && app._router.stack
        const routes = getRoutes(entryPoint)

        const info = routes
                .reduce((result, it) => {
                        const [ method, path ] = it

                        return result + `${method.padEnd(6)} ${path}\n`
                }, '')

        return info
}

Update 1:

Due to the internal limitations of Express 4 it is not possible to retrieve mounted app and mounted routers. For example it is not possible to obtain routes from this configuration.

const subApp = express()
app.use('/sub/app', subApp)

const subRouter = express.Router()
app.use('/sub/route', subRouter)

Within your app at /routes display your express route names

app.get('/routes', (req, res) => {
    res.send(app._router.stack
        .filter(r => r.route) 
        .map(r => r.route.path))
})

http://localhost:3000/routes


Examples related to node.js

Hide Signs that Meteor.js was Used Querying date field in MongoDB with Mongoose SyntaxError: Cannot use import statement outside a module Server Discovery And Monitoring engine is deprecated How to fix ReferenceError: primordials is not defined in node UnhandledPromiseRejectionWarning: This error originated either by throwing inside of an async function without a catch block dyld: Library not loaded: /usr/local/opt/icu4c/lib/libicui18n.62.dylib error running php after installing node with brew on Mac internal/modules/cjs/loader.js:582 throw err DeprecationWarning: Buffer() is deprecated due to security and usability issues when I move my script to another server Please run `npm cache clean`

Examples related to express

UnhandledPromiseRejectionWarning: This error originated either by throwing inside of an async function without a catch block jwt check if token expired Avoid "current URL string parser is deprecated" warning by setting useNewUrlParser to true MongoNetworkError: failed to connect to server [localhost:27017] on first connect [MongoNetworkError: connect ECONNREFUSED 127.0.0.1:27017] npm notice created a lockfile as package-lock.json. You should commit this file Make Axios send cookies in its requests automatically What does body-parser do with express? SyntaxError: Unexpected token function - Async Await Nodejs Route.get() requires callback functions but got a "object Undefined" How to redirect to another page in node.js