web-dev-qa-db-fra.com

Comment obtenir tous les itinéraires enregistrés dans Express?

J'ai une application Web créée à l'aide de Node.js et Express. Maintenant, je voudrais lister tous les itinéraires enregistrés avec leurs méthodes appropriées.

Par exemple, si j'ai exécuté

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

Je voudrais récupérer un objet (ou quelque chose d'équivalent à cela) tel que:

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

Est-ce possible, et si oui comment?


UPDATE: Pendant ce temps, j'ai créé un paquet npm appelé get-routes qui extrait les routes d'une application donnée, ce qui résout ce problème. Actuellement, seul Express 4.x est pris en charge, mais je suppose que cela va pour le moment. Juste FYI.

141
Golo Roden

express 3.x

Ok, je l'ai trouvé moi-même ... c'est juste app.routes :-)

express 4.x

Applications - construit avec express()

app._router.stack

Routeurs - construits avec express.Router()

router.stack

Note: La pile inclut aussi les fonctions de middleware, elle devrait être filtrée pour obtenir le "routes" uniquement.

179
Golo Roden
app._router.stack.forEach(function(r){
  if (r.route && r.route.path){
    console.log(r.route.path)
  }
})
44
eychu

J'ai adapté un ancien message qui n'est plus en ligne pour mes besoins . J'ai utilisé express.Router () et enregistré mes itinéraires comme suit:

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

J'ai renommé le fichier document.js en apiTable.js et je l'ai adapté comme suit:

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;
};

alors je l'appelle dans mon server.js comme ceci:

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

Le résultat ressemble à ceci:

Result example

C'est juste un exemple, mais pourrait être utile .. j'espère ..

27
marco.marinangeli

Voici une petite chose que j'utilise simplement pour obtenir les chemins enregistrés dans 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
26
corvid

Cela permet d'obtenir des itinéraires enregistrés directement sur l'application (via app.VERB) et des itinéraires enregistrés comme middleware de routeur (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}}
23
Caleb

Hacky copier/coller avec la permission de Doug Wilson sur les problèmes de express github Sale mais fonctionne comme un charme.

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, []))

Produit 

screengrab

7
AlienWebguy

Une fonction pour enregistrer toutes les routes dans Express 4 (peut être facilement modifiée pour la 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);

Journaux en sortie: 

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

Fait de cela un NGP https://www.npmjs.com/package/express-list-routes

7
Labithiotis

https://www.npmjs.com/package/express-list-endpoints fonctionne plutôt bien.

Exemple

Usage:

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

Sortie:

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

Express 4

Avec une configuration Express 4 avec des noeuds finaux et des routeurs imbriqués

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

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

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

app.use(router)

En développant la réponse @caleb , il est possible d'obtenir tous les itinéraires de manière récursive et triés.

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
}

Pour une sortie de chaîne de base.

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
}

Mise à jour 1:

En raison des limitations internes d'Express 4, il n'est pas possible de récupérer l'application montée et les routeurs montés. Par exemple, il n'est pas possible d'obtenir des itinéraires à partir de cette configuration.

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

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

DEBUG=express:* node index.js

Si vous exécutez votre application avec la commande ci-dessus, elle sera lancée avec le module DEBUG et donnera les itinéraires, ainsi que toutes les fonctions middleware en cours d'utilisation.

Vous pouvez vous référer à: ExpressJS - Debugging et debug .

4
nbsamar

Besoin de quelques ajustements mais devrait fonctionner pour Express v4. Y compris les itinéraires ajoutés avec .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: améliorations du code

4
lcssanches

Les itinéraires express-list-list de Labithiotis m'ont inspiré, mais je souhaitais avoir une vue d'ensemble de tous mes itinéraires et de mes URL brutes, sans spécifier de routeur, et déterminer le préfixe à chaque fois. Je suis parvenu à remplacer la fonction app.use par ma propre fonction qui stocke la baseUrl et le routeur en question. De là, je peux imprimer n’importe quel tableau de tous mes itinéraires.

NOTE: cela fonctionne pour moi car je déclare mes routes dans un fichier de routes spécifique (fonction) qui est passé dans l'objet app, comme ceci:

// 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);
}

Cela me permet de passer dans un autre objet 'app' avec une fonction d'utilisation fictive, et je peux obtenir TOUS les itinéraires. Cela fonctionne pour moi (suppression d'une vérification d'erreur pour la clarté, mais fonctionne toujours pour l'exemple):

// 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);
    }
  });
});

Cet exemple complet (avec quelques routeurs CRUD de base) vient d'être testé et imprimé:

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

Utiliser cli-table J'ai quelque chose comme ça:

┌────────┬───────────────────────┐
│        │ => 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 │
└────────┴───────────────────────────────────┘

Ce qui frappe le cul.

4
Yann Vanhalewyn

Approche légèrement actualisée et plus fonctionnelle de la réponse de @ prranay:

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));
2
SeedyROM

Cela a fonctionné pour moi

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"
]
2
prranay

sortie json

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));

ressemble à ça:

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

sortie de chaîne

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());

ressemble à ça:

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

ceux-ci sont basés sur @ corvid answer

j'espère que cela t'aides

1
ezekills

Donc, je cherchais toutes les réponses… je n'ai pas aimé la plupart… j'en ai pris quelques unes… a fait ceci:

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);

pas la plus jolie .. mais imbriquée, et fait le tour

notez également le 20 là ... Je suppose juste qu'il n'y aura pas de route normale avec 20 méthodes .. donc j'en déduis que c'est tout ..

1
TacB0sS

les détails de route sont la liste route pour "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 SORTIE DE 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"}
]
0

J'ai publié un package qui imprime tous les middlewares ainsi que les itinéraires, ce qui est très utile pour essayer d'auditer une application express. Vous montez le paquet en tant que middleware, de sorte qu'il s'imprime même:

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

Il imprime une sorte d'arbre comme:

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

Sur Express 3.5.x, j'ajoute ceci avant de démarrer l'application pour imprimer les itinéraires sur mon terminal:

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

Peut-être que ça peut aider ...

0
David Manson