Как получить все зарегистрированные маршруты в Express?
У меня есть веб-приложение, построенное с использованием Node.js и Express. Теперь я хотел бы перечислить все зарегистрированные маршруты с помощью соответствующих методов.
Например, если я выполнил
app.get('/', function (...) { ... });
app.get('/foo/:id', function (...) { ... });
app.post('/foo/:id', function (...) { ... });
Я хотел бы получить объект (или что-то подобное этому), например:
{
get: [ '/', '/foo/:id' ],
post: [ '/foo/:id' ]
}
Возможно ли это, и если да, то как?
UPDATE:. Между тем, я создал пакет npm под названием get-routes, который извлекает маршруты из заданного приложение, которое решает эту проблему. В настоящее время поддерживается только Express 4.x, но на данный момент я думаю, что это нормально. Просто FYI.
Ответы
Ответ 1
express 3.x
Хорошо, нашел это сам... это просто app.routes
: -)
express 4.x
Приложения - построено с помощью express()
app._router.stack
Маршрутизаторы - построены с помощью express.Router()
router.stack
Примечание. В стек также входят функции промежуточного программного обеспечения, его следует фильтровать, чтобы получить только "маршруты".
Ответ 2
app._router.stack.forEach(function(r){
if (r.route && r.route.path){
console.log(r.route.path)
}
})
Ответ 3
Я адаптировал старый пост, который больше не находится в сети, для моих нужд. Я использовал express.Router() и зарегистрировал свои маршруты следующим образом:
var questionsRoute = require('./BE/routes/questions');
app.use('/api/questions', questionsRoute);
Я переименовал файл document.js в apiTable.js и адаптировал его так:
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;
};
тогда я называю это в моем server.js как это:
var server = app.listen(process.env.PORT || 5000, function () {
require('./BE/utils/apiTable')('/api/questions', questionsRoute.stack);
});
Результат выглядит так:
![Result example]()
Это просто пример, но может быть полезным.. я надеюсь..
Ответ 4
Вот небольшая вещь, которую я использую, чтобы получить зарегистрированные пути в 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
Ответ 5
Это получает маршруты, зарегистрированные непосредственно в приложении (через app.VERB) и маршруты, зарегистрированные в качестве промежуточного ПО маршрутизатора (через app.use). Экспресс 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}}
Ответ 6
Hacky copy/paste ответ любезно предоставлен Дугом Уилсоном по вопросам экспресс-github. Грязный, но работает как шарм.
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, []))
Производит
![screengrab]()
Ответ 7
https://www.npmjs.com/package/express-list-endpoints работает довольно хорошо.
пример
Использование:
const all_routes = require('express-list-endpoints');
console.log(all_routes(app));
Выход:
[ { path: '*', methods: [ 'OPTIONS' ] },
{ path: '/', methods: [ 'GET' ] },
{ path: '/sessions', methods: [ 'POST' ] },
{ path: '/sessions', methods: [ 'DELETE' ] },
{ path: '/users', methods: [ 'GET' ] },
{ path: '/users', methods: [ 'POST' ] } ]
Ответ 8
Функция для регистрации всех маршрутов в express 4 (может быть легко изменена для 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);
Выход журналов:
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
Сделано это в NPM https://www.npmjs.com/package/express-list-routes
Ответ 9
DEBUG=express:* node index.js
Если вы запустите приложение с помощью указанной выше команды, оно запустит ваше приложение с модулем DEBUG
и предоставит маршруты, а также все используемые функции промежуточного программного обеспечения.
Вы можете сослаться на: ExpressJS - отладка и отладка.
Ответ 10
Я был вдохновлен экспресс-списками Labithiotis, но мне хотелось получить общий обзор всех моих маршрутов и грубых URL-адресов за один раз, а не указывать маршрутизатор и каждый раз определять префикс. Что-то, с чем я столкнулся, это просто заменить функцию app.use моей собственной функцией, которая хранит baseUrl и данный маршрутизатор. Оттуда я могу распечатать любую таблицу всех моих маршрутов.
ПРИМЕЧАНИЕ, это работает для меня, потому что я объявляю свои маршруты в определенном файле маршрута (функции), который передается в объекте приложения, например:
// 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);
}
Это позволяет мне передать другой объект "app" с помощью функции поддельного использования, и я могу получить ВСЕ маршруты. Это работает для меня (удалена некоторая проверка ошибок для ясности, но все еще работает для примера):
// 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);
}
});
});
Этот полный пример (с некоторыми базовыми маршрутизаторами CRUD) был просто протестирован и распечатан:
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
Использование cli-table У меня есть что-то вроде этого:
┌────────┬───────────────────────┐
│ │ => 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 │
└────────┴───────────────────────────────────┘
Какая пинает задницу.
Ответ 11
Экспресс 4
Учитывая конфигурацию Express 4 с конечными точками и вложенными маршрутизаторами
const express = require('express')
const app = express()
const router = express.Router()
app.get(...)
app.post(...)
router.use(...)
router.get(...)
router.post(...)
app.use(router)
Развернув ответ @caleb, можно получить все маршруты рекурсивно и отсортировано.
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
}
Для основного вывода строки.
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
}
Обновление 1:
Из-за внутренних ограничений Express 4 невозможно получить смонтированное приложение и смонтированные маршрутизаторы. Например, невозможно получить маршруты из этой конфигурации.
const subApp = express()
app.use('/sub/app', subApp)
const subRouter = express.Router()
app.use('/sub/route', subRouter)
Ответ 12
Нужны некоторые настройки, но должны работать для Express v4. Включая эти маршруты, добавленные с помощью .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", "..."]
редактировать: улучшения кода
Ответ 13
Это сработало для меня
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"
]
Ответ 14
Немного обновленный и более функциональный подход к @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));
Ответ 15
Так что я смотрел на все ответы.. не понравилось больше всего.. взял несколько из нескольких.. сделал это:
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);
не самая красивая.. но вложенная и делает свое дело
также обратите внимание на 20 там... Я просто предполагаю, что не будет нормального маршрута с 20 методами.. поэтому я вывести это все..
Ответ 16
выход 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));
выглядит так:
[
{
"method": "GET",
"path": "/api/todos"
},
{
"method": "POST",
"path": "/api/todos"
},
{
"method": "PUT",
"path": "/api/todos/:id"
},
{
"method": "DELETE",
"path": "/api/todos/:id"
}
]
вывод строки
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());
выглядит так:
GET /api/todos
POST /api/todos
PUT /api/todos/:id
DELETE /api/todos/:id
они основаны на ответе @corvid
надеюсь это поможет
Ответ 17
В Express 3.5.x, я добавляю это перед запуском приложения для печати маршрутов на моем терминале:
var routes = app.routes;
for (var verb in routes){
if (routes.hasOwnProperty(verb)) {
routes[verb].forEach(function(route){
console.log(verb + " : "+route['path']);
});
}
}
Может быть, это может помочь...
Ответ 18
детали маршрута перечисляют маршрут для "экспресс": "4.xx",
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));
});
ПРОСТОЙ ВЫХОД КОДА
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"}
]
Ответ 19
Я опубликовал пакет, который печатает все промежуточное программное обеспечение, а также маршруты, очень полезные при проверке экспресс-приложения. Вы монтируете пакет как промежуточное ПО, так что он даже сам печатает:
https://github.com/ErisDS/middleware-stack-printer
Он печатает своего рода дерево, как:
- middleware 1
- middleware 2
- Route /thing/
- - middleware 3
- - controller (HTTP VERB)
Ответ 20
Просто используйте этот пакет npm, он даст веб-вывод, а также вывод для терминала в хорошем отформатированном табличном представлении.
![enter image description here]()
https://www.npmjs.com/package/express-routes-catalogue