Closed noinkling closed 2 years ago
Closed via #143
We have just published @koajs/router
v11.0.0 which resolves this issue. This is mirrored to koa-router
as well.
https://github.com/koajs/router/releases/tag/v11.0.0
This project is maintained by Forward Email and Lad.
node.js version: 16.13.2
@koa/router
version: 10.1.1koa
version: 2.13.4Explanation:
In order to get the full path of a named route in a nested router using the
.url()
method, we have to call it on the base router (same principle applies for.redirect()
and.route()
):This is a little bit of a pain to remember, but makes sense when you consider that a nested router can't know where it's mounted (at least, not until request time), especially since it could potentially be mounted multiple times in different places. I think a note about this should probably be made in the docs, especially considering that in some previous versions (I know in 7.4.0 at least), calling
.url()
did actually give the full path... as long as you only mounted each router only once, otherwise it was very broken. It's easy to not realise that the behaviour changed.That's only a minor issue, the bigger problem is that since we have to use the base router, the names we give to any routes have to be unique across the whole routing tree, or else there's no guarantee we'll get the one we expect. For example if we re-use
fooRouter
for v2 of the API like so:a POST request to
http://localhost:3000/api/v2/foos
will log thev1
path instead.Additionally, if we created a
barRouter
with the same structure asfooRouter
(maybe we're using an abstraction like a factory to create routers for resources), we could run into a similar collision where the path for abar
resource is returned instead of afoo
, or vice versa.Workaround:
Since the route identifiers need to be globally unique, on a whim I tried using symbols in place of strings, which turns out to already work as-is! All you have to do is make sure you're not sharing references to the same symbol. The only issues I found with this approach are:
name
would just need to be wrapped inString()
or similar.Do you think this approach should be supported/documented (since there's almost no work needed), or should we look for a way to solve the issue that's a little more ergonomic?