Add Router proxy with enforced prefix
opl- opened this issue · comments
A common pattern for me appears to be creating a new Router
instance to create a "namespace" of routes. For example, I might create a new Router
for all paths starting with /api/user/:userId
, on which I will register all endpoints which relate to a specific user: /activity
, /posts
, /ban
(all with the implicit /api/user/:userId
prefix). This is done to avoid repetition, and reduce potential for typos or incomplete refactors.
This does work, but makes it more difficult to register middleware (see #1), makes debugging more difficult and possibly increases overhead (the route processing goes through multiple Router
handlers), and, if the routes are registered in a different file, makes it more difficult to immediately see what the path prefix is.
A possible pattern to improve this is to introduce a proxy Router
, which will always prefix all registered paths with a set prefix.
Exposing this as a Router
method would also create a convenient way to expand the context types for all the routes declared under it, for example to introduce the userId
param, or a resolved User
instance in the state
.
const apiRouter = new Router();
interface UserRouterContext {
params: {
userId: string;
};
state: {
user: User;
};
}
// TODO: Function name to be determined (prefix, namespace?).
const userPrefix = apiRouter.createPrefix<{}, UserRouterContext>('/api/user/:userId');
userPrefix.use('/*', async (ctx, next) => {
const user = await User.byId(ctx.params.userId);
if (!user) {
ctx.status = 404;
return;
}
ctx.user = user;
await next();
});