Jak odebrać wszystkie zarejestrowane trasy ekspresem?


Mam aplikację internetową zbudowaną przy użyciu Node.js i Express. Teraz chciałbym wymienić wszystkie zarejestrowane trasy z odpowiednimi metodami.
Np. Jeśli się spełniłem
app.get('/', function (...) { ... });
app.get('/foo/:id', function (...) { ... });
app.post('/foo/:id', function (...) { ... });

Chciałbym otrzymać obiekt (lub coś równoważnego temu), na przykład:
{
get: [ '/', '/foo/:id' ],
post: [ '/foo/:id' ]
}

Czy to możliwe, a jeśli tak, to w jaki sposób?

UPDATE:

w międzyczasie utworzyłem pakiet npm o nazwie

get-routes
https://www.npmjs.com/package/get-routes
który pobiera trasy z danej aplikacji, co rozwiązuje ten problem. Obecnie obsługiwany jest tylko Express 4.x, ale myślę, że na razie jest to w porządku. Po prostu FYI.
Zaproszony:
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:


ekspresowe 3.x
>
Ok, znalazłem to sam ... to po prostu
app.routes
:-)

express 4.x
>
Aplikacje
http://expressjs.com/4x/api.html#express
zbudowany za pomocą
express ()

app._router.stack

Routery
http://expressjs.com/4x/api.html#router
-zbudowany z
express.Router ()

router.stack


Uwaga
: stos zawiera również funkcje oprogramowania pośredniego, należy go przefiltrować, aby uzyskać
tylko „trasy”.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

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

Anonimowy użytkownik

Potwierdzenie od:

Dostosowałem stary post, który nie jest już online, do moich potrzeb.
Użyłem express.Router () i zarejestrowałem moje trasy w ten sposób:
var questionsRoute = require('./BE/routes/questions');
app.use('/api/questions', questionsRoute);

Zmieniłem nazwę pliku document.js na apiTable.js i dostosowałem go w następujący sposób:
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;
};

wtedy nazywam to w moim server.js w ten sposób:
var server = app.listen(process.env.PORT || 5000, function () {
require('./BE/utils/apiTable')('/api/questions', questionsRoute.stack);
});

Wynik wygląda następująco:
To tylko przykład, ale może być pomocny ... Mam nadzieję ...
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Powoduje to rejestrowanie tras bezpośrednio w aplikacji (przez app.VERB) i rejestrowanie tras jako oprogramowanie pośredniczące routera (przez 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}}
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Oto mała rzecz, której używam tylko do uzyskiwania zarejestrowanych ścieżek w 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
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

DEBUG=express:* node index.js
Jeśli uruchomisz swoją aplikację za pomocą powyższego polecenia, uruchomi ona aplikację z modułem
DEBUG
i poda trasy, a także wszystkie używane funkcje oprogramowania pośredniego.
Możesz się skontaktować:

Debugowanie ExpressJS
https://expressjs.com/en/guide/debugging.html
i

debugowanie
https://www.npmjs.com/package/debug
.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

„Sox” kopiuj/wklej odpowiedź dzięki uprzejmości

Doug Wilson
https://github.com/dougwilson
na

wyrażaj pytania na github
https://github.com/expressjs/e ... 08... Brudne, ale działa jak zaklęcie.
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, []))

Produkuje
https://i.stack.imgur.com/CkUrX.png
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

https://www.npmjs.com/package/ ... oints
https://www.npmjs.com/package/ ... oints
działa całkiem nieźle.

Przykład

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

Wyjście:
[ { path: '*', methods: [ 'OPTIONS' ] },
{ path: '/', methods: [ 'GET' ] },
{ path: '/sessions', methods: [ 'POST' ] },
{ path: '/sessions', methods: [ 'DELETE' ] },
{ path: '/users', methods: [ 'GET' ] },
{ path: '/users', methods: [ 'POST' ] } ]
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Funkcja logowania wszystkich tras w Express 4 (można ją łatwo skonfigurować dla 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);

Dzienniki produkcyjne:
GET/isAlive
POST/test/email
POST/user/verifyPUT/login
POST/login
GET/player
PUT/player
GET/player/:id
GET/players
GET/system
POST/user
GET/user
PUT/user
DELETE/userGET/
GET/login


Zamieniłem to w NPM

https://www.npmjs.com/package/express-list-routes
https://www.npmjs.com/package/express-list-routes
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:


JSON wyjście
>
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));

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


wyjście ciągu
>
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());

wygląda tak:
GET/api/todos 
POST/api/todos
PUT/api/todos/:id
DELETE/api/todos/:id

są oparte na odpowiedzi

@corvid's
https://stackoverflow.com/a/35089029/8472592
mam nadzieję że to pomoże
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Zainspirowały mnie trasy ekspresowej listy Labitiotis, ale chciałem uzyskać przegląd wszystkich moich tras i przybliżonych adresów URL za jednym razem, zamiast określać router i za każdym razem obliczać prefiks. Wymyśliłem po prostu zastąpienie funkcji app.use moją własną funkcją, która przechowuje baseUrl i dany router. Stamtąd mogę wydrukować dowolną tabelę wszystkich moich tras.
UWAGA to działa dla mnie, ponieważ deklaruję moje trasy w określonym pliku tras (funkcji), który jest przekazywany do obiektu aplikacji, np .:
// 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);
}

To pozwala mi przekazać inny obiekt „aplikacji” z fałszywą funkcją użycia i mogę uzyskać WSZYSTKIE trasy. To działa dla mnie (usunięto niektóre sprawdzanie błędów dla jasności, ale nadal działa dla przykładu):
// 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);
}
});
});

Ten kompletny przykład (z kilkoma podstawowymi routerami CRUD) został właśnie przetestowany i wydrukowany:
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

Za pomocą

cli-table
https://www.npmjs.com/package/cli-table, Mam coś takiego:
┌────────┬───────────────────────┐
│ │ => 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 │
└────────┴───────────────────────────────────┘

To kopie cię w dupę.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:


Express 4
>
Dany

Express-4

konfiguracje końcowe i routery zagnieżdżone
<pre class="lang-js prettyprint-override">
const express = require('express')
const app = express()
const router = express.Router()app.get(...)
app.post(...)router.use(...)
router.get(...)
router.post(...)app.use(router)

Rozwijając odpowiedź @ caleb, możliwe jest rekursywne pobieranie i sortowanie wszystkich tras.
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
}

Do podstawowego wyjścia string.
infoAboutRoutes(app)

https://i.stack.imgur.com/9Xt0A.png
/**
* 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
}


Aktualizacja 1:
>
Ze względu na wewnętrzne ograniczenia Express 4 nie jest możliwe zamontowanie aplikacji i zamontowanie routerów. Na przykład nie jest możliwe pobranie tras z tej konfiguracji.
const subApp = express()
app.use('/sub/app', subApp)const subRouter = express.Router()
app.use('/sub/route', subRouter)
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Potrzebne są pewne poprawki, ale powinny działać w przypadku Express v4. W tym trasy, które zostały dodane za pomocą
.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", "..."]

edycja: ulepszenia kodu
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Możesz zaimplementować interfejs API
/ get-all-Routes
:
<pre class="lang-js prettyprint-override">
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);
});

Oto demo:

https://glitch.com/edit/%23%21 ... odejs
https://glitch.com/edit/%23%21 ... odejs
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Nieco zaktualizowane i bardziej funkcjonalne podejście do odpowiedzi @ 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));
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:


Ekspresowa inicjalizacja routera

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!',
});
});
Importowanie niestandardowego kontrolera

var userController = require('./controller/userController');
Trasy użytkowników

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 Route API

module.exports = router;


Wyjście

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

Anonimowy użytkownik

Potwierdzenie od:

To zadziałało dla mnie
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"
]
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

W Express 3.5.x dodaję to przed uruchomieniem aplikacji do drukowania tras na moim terminalu:
var routes = app.routes;
for (var verb in routes){
if (routes.hasOwnProperty(verb)) {
routes[verb].forEach(function(route){
console.log(verb + " : "+route['path']);
});
}
}

Może to pomoże ...
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

szczegółowe informacje o trasie zawierają listę tras dla „ekspresu”: „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('[b]List of routes.[/b]>' + JSON.stringify(routes));
});

PROSTE WYJŚCIE KODU
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"}
]
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Szukałem więc odpowiedzi na wszystkie pytania ... większości się to nie podobało ... wziąłem coś z kilku ... zrobiłem to:
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);

nie najpiękniejszy ... ale zagnieżdżony i spełnia swoje zadanie
zwróć też uwagę na 20 tam ... Zgaduję, że nie będzie normalnej trasy z 20 metodami .. więc dochodzę do wniosku, że to wszystko ..
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Po prostu użyj tego pakietu npm, da on wyjście do sieci, a także wyjście terminala w ładnie sformatowanej formie tabelarycznej.
https://i.stack.imgur.com/iNnKn.png
https://www.npmjs.com/package/ ... talog
https://www.npmjs.com/package/ ... logue
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Ekspresowy 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)
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Opublikowałem pakiet, który drukuje całe oprogramowanie pośrednie, a także trasy, co jest bardzo przydatne podczas próby audytu aplikacji ekspresowej. Używasz pakietu jako oprogramowania pośredniego, więc nawet sam się drukuje:
https://github.com/ErisDS/middleware-stack-printer
https://github.com/ErisDS/middleware-stack-printer
Wyświetla coś w rodzaju drzewa, na przykład:
- middleware 1
- middleware 2
- Route/thing/
- - middleware 3
- - controller (HTTP VERB)
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Oto jednowierszowa funkcja do ładnego drukowania tras w
app
express:
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();

Aby odpowiedzieć na pytania, Zaloguj się lub Zarejestruj się