-
-
Notifications
You must be signed in to change notification settings - Fork 17.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to get route name of parent route? #2879
Comments
I was actually looking at this exact feature recently, so we could stat the routes getting hit. We ended up just passing an identifier to the last middleware where we knew its "final form". We did this because the router/route do now know about mounting. It would be a relatively simple task to make the |
Related to #2501 |
@wesleytodd @tunniclm Thanks for your feedback - nice to see that I'm not the only one who've been struggling with this. I guess I'll have to monkey patch my way out of this for the time being and wait for proper support to land in Express v5 😃 |
@watson NP! Also might want to take a look at using
Haven't tested that, but it might solve your issue. |
@wesleytodd It just returns an empty string in my case. It seems to depend on the |
It does return an empty string when NOT in a mounted app. But when you mount like in your OP you should get the mount path. Is that not working? |
@wesleytodd Seems not to work in my app. I've made a simple express app showing it. The app in the linked gist will log the following if
Update: The string I'm looking to extract is |
Looks like it doesnt work with just a router instance, and only with a full express app instance. I pulled down your gist and changed
|
@wesleytodd Interesting. Thanks for clearing that up. Unfortunately I need it to work for instances of |
Yeah, this clearly seems like something worth changing in express and the router. I think opening up an issue on the router is still a good idea. |
@wesleytodd Ah I see. The reason why the I've just been looking through the code and as far as I can see the path given as the 1st argument to the |
@wesleytodd wouldn't it maybe be ok to check if the sub-app was an instance of the |
That behavior seems accurate to what I know. This might be a question for @dougwilson or @jasnell for the breaking change question. |
I was at lunch when i answered last, so I didn't want to type too much. But now that I am back, I think that technically this is not a breaking change. But any change to a public api has fallout that can be un-anticipated, so maybe patching it in your application and then applying the changes to v5 would be best. To patch it in your app all you need to do is override |
@wesleytodd To prevent having to replicate the entire First shim the var origUse = express.Router.use
express.Router.use = function (fn) {
if (typeof fn === 'string' && Array.isArray(this.stack)) {
var offset = this.stack.length
var result = origUse.apply(this, arguments)
var layer
for (; offset < this.stack.length; offset++) {
layer = this.stack[offset]
// I'm not sure if my check for `fast_slash` is the way to go here
// But if I don't check for it, each stack element will add a slash to the path
if (layer && layer.regexp && !layer.regexp.fast_slash) layer.__mountpath = fn
}
return result
} else {
return origUse.apply(this, arguments)
}
} Then shim the var origPP = express.Router.process_params
express.Router.process_params = function (layer, called, req, res, done) {
var path = req.route && (req.route.path || req.route.regexp && req.route.regexp.source) ||
layer.__mountpath ||
''
req.__route = (req.__route || '') + path
return origPP.apply(this, arguments)
} This will add a |
Nice! Certainly monkey patching is not fun in the long run, but hopefully we can add this in 5 and you can switch over sometime soon :) |
@watson That work for me! Thank you very much! |
@watson The above works! Thank you. In the above case if my middleware against '/mountpath' throws an error, then inside 'middlewareErrorHandler' I would see __route with '/mountpath' duplicated once and in the next error handler, i see it twice. Am not sure the right way to fix this, but i put the below fix (ofcse the below will be erroneous if someone's URL naming scheme has duplicated path, but not sure if someone would do that :)). Nevertheless would appreciate if there is a better way, please advise.
|
Hello! |
Another approach that avoids the monkey-patching issue is the following:
Notice that conflict resolution (i.e two params that were resolved to the same value) can be implemented in whichever way you choose. Since we use uuids in our app, this should never happen in our routes. This is why we decided to resolve this conflict using |
@asheba Wow! Thank so so much for this! You saved my day! :) |
Thank you all for the various solutions! It helped guide me to this alternative which also avoids monkey-patching, in addition to not requiring setting // Middleware callback to provide to .use before Routes are defined
const logMatchedRoute = (req, res, next) => {
// Add getter and setter for req.params
Object.defineProperty(req, 'params', {
get() {
return this.__params;
},
set(params) {
// If __matchroute is empty, set as full URL (except ? queries)
if (!this.__matchroute) {
this.__matchroute = this.baseUrl + this.path;
}
// Loop through params and replace the first matching value with :{param_name}
for (const key in params) {
if (Object.hasOwnProperty.call(params, key)) {
const val = params[key];
this.__matchroute = this.__matchroute.replace(`/${val}`, `/:${key}`);
}
}
this.__params = params;
}
});
// Log matched route when response is closed
res.on('close', () => {
console.log('__matchroute', req.__matchroute);
});
next();
}; |
Goal
For each incoming request I'd like to log the name of the route that matches the request. So given the request
GET /users/42
which matches theapp.use('/users/:id', ...)
route handler I'd like to get the name/users/:id
.Partial solution
I originally used the
route
property on the request object to extract the route name:Problem
But the above solution doesn't work for nested routes, e.g:
When mounting a route like in the above example, the
req.route.path
property will not contain the parent route. So if someone requestsGET /admin/users/42
thenreq.route.path
would just contain/users/:id
and not/a(dmin)?/users/:id
.Is there any way inside a route handler to figure out that this was routed through a parent route with the name
/a(dmin)?
?I first thought to use
req.baseUrl
, but that will give me the "resolved" path, so I'd get either/a
or/admin
depending on which actual URL the user typed - I'd like to get the generic route name instead:/a(dmin)?
If this is not possible at all in v4, it would be cool if this could be supported in v5 😃
The text was updated successfully, but these errors were encountered: