webentwicklung-frage-antwort-db.com.de

Wie bekomme ich alle registrierten Routen in Express?

Ich habe eine Webanwendung, die mit Node.js und Express erstellt wurde. Nun möchte ich alle registrierten Routen mit den entsprechenden Methoden auflisten.

Zum Beispiel, wenn ich ausgeführt habe

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

Ich möchte ein Objekt abrufen (oder etwas Äquivalentes dazu) wie:

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

Ist das möglich und wenn ja, wie?


UPDATE: Inzwischen habe ich ein npm-Paket mit dem Namen get-routes erstellt, das die Routen aus einer bestimmten Anwendung extrahiert, wodurch dieses Problem gelöst wird. Momentan wird nur Express 4.x unterstützt, aber für den Moment ist dies in Ordnung. Nur zur Info.

141
Golo Roden

drücken Sie 3.x aus

Okay, hab es selbst gefunden ... es ist nur app.routes :-)

drücken Sie 4.x aus

Anwendungen - erstellt mit express()

app._router.stack

Router - erstellt mit express.Router()

router.stack

Note: Der Stack enthält auch die Middleware-Funktionen. Er sollte gefiltert werden, um nur die "routen" zu erhalten.

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

Ich habe einen alten Beitrag angepasst, der nicht mehr für meine Bedürfnisse online ist .. Ich habe express.Router () verwendet und meine Routen wie folgt registriert:

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

Ich habe die document.js-Datei in apiTable.js umbenannt und wie folgt angepasst:

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

dann nenne ich es in meinem server.js so:

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

Das Ergebnis sieht so aus:

Result example

Es ist nur ein Beispiel, aber es könnte nützlich sein .. ich hoffe ..

27

Hier ist eine Kleinigkeit, die ich nur benutze, um die registrierten Pfade in Express 4.x zu erhalten

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

Dadurch werden Routen direkt in der App (via app.VERB) und Routen, die als Router-Middleware (via app.use) registriert sind, registriert. 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 Antwort kopieren/einfügen, mit freundlicher Genehmigung von Doug Wilson zu den express github Ausgaben . Dirty aber wirkt wie ein Zauber.

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

Produziert 

 screengrab

7
AlienWebguy

Eine Funktion zum Protokollieren aller Routen in Express 4 (kann leicht für v3 ~ angepasst werden)

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

Protokollausgabe: 

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

Aus einem NPM gemacht https://www.npmjs.com/package/express-list-routes

7
Labithiotis

https://www.npmjs.com/package/express-list-endpoints funktioniert ziemlich gut.

Beispiel

Verwendungszweck:

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

Ausgabe:

[ { 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

Eine Express 4 -Konfiguration mit Endpunkten und verschachtelten Routern gegeben

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

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

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

app.use(router)

Durch die Erweiterung der Antwort @caleb können alle Routen rekursiv und sortiert abgerufen werden.

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
}

Für die grundlegende String-Ausgabe.

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:

Aufgrund der internen Einschränkungen von Express 4 ist es nicht möglich, eingehängte Apps und eingebaute Router abzurufen. Es ist beispielsweise nicht möglich, Routen aus dieser Konfiguration abzurufen.

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

Wenn Sie Ihre App mit dem obigen Befehl ausführen, startet sie Ihre App mit dem Modul DEBUG und gibt Routen sowie alle verwendeten Middleware-Funktionen an.

Sie können verweisen auf: ExpressJS - Debugging und debug .

4
nbsamar

Benötigen Sie einige Anpassungen, sollten aber für Express v4 funktionieren. Einschließlich der mit .use() hinzugefügten Routen.

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", "..."]

bearbeiten: Code-Verbesserungen

4
lcssanches

Ich wurde von Labithiotis 'Express-Listen-Routen' inspiriert, wollte aber auf einen Blick einen Überblick über alle meine Routen und URLs auf einmal haben, keinen Router angeben und jedes Mal den Präfix ermitteln. Ich kam auf die Idee, einfach die app.use-Funktion durch meine eigene Funktion zu ersetzen, die die baseUrl und den angegebenen Router speichert. Von dort kann ich jede meiner Routen ausdrucken.

HINWEIS: Dies funktioniert für mich, weil ich meine Routen in einer bestimmten Routendatei (Funktion) deklariere, die im App-Objekt übergeben wird, z.

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

Dadurch kann ich ein anderes "App" -Objekt mit einer Fake-Use-Funktion übergeben, und ich kann ALLE Routen erhalten. Dies funktioniert für mich (einige Fehler wurden zur besseren Übersichtlichkeit entfernt, funktionieren aber weiterhin für das Beispiel):

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

Dieses vollständige Beispiel (mit einigen einfachen CRUD-Routern) wurde gerade getestet und ausgedruckt:

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

Mit cli-table habe ich so etwas bekommen:

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

Welcher Arsch tritt.

4
Yann Vanhalewyn

Etwas aktualisierter und funktionalerer Ansatz für die Antwort von @ 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

Das hat bei mir funktioniert

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

json ausgang

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

sieht aus wie das:

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

string-Ausgabe

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

sieht aus wie das:

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

diese basieren auf @ corvids Antwort

hoffe das hilft

1
ezekills

Also schaute ich mir alle Antworten an ... mochte nicht am meisten .. nahm einige von ein paar .. machte folgendes:

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

nicht das schönste .. aber geschachtelt und macht den trick

beachten Sie auch die 20 dort ... Ich gehe einfach davon aus, dass es mit 20 Methoden keine normale Route geben wird.

1
TacB0sS

routendetails sind eine Auflistung der Route für "Express":

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

EINFACHE AUSGABE VON 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"}
]

Ich habe ein Paket veröffentlicht, das alle Middleware sowie Routen druckt. Dies ist sehr nützlich, wenn Sie versuchen, eine Expressanwendung zu prüfen. Sie mounten das Paket als Middleware, so dass es sogar selbst ausgedruckt wird:

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

Es druckt eine Art Baum wie:

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

In Express 3.5.x füge ich dies hinzu, bevor ich die App starte, um die Routen auf meinem Terminal zu drucken:

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

Vielleicht kann es helfen ...

0
David Manson