koajs / joi-router

Configurable, input and output validated routing for koa
MIT License
450 stars 96 forks source link

Nested router prefix #43

Closed thakkaryash94 closed 5 years ago

thakkaryash94 commented 7 years ago

How I can have sub router with prefix and add main router with another prefix?

userRoutes.js

import router from 'koa-joi-router';
const userRouter = router();
userRouter.prefix('/user');
const userRoutes = [...];
userRouter.route(userRoutes);
export default userRouter;

mainRoutes.js

import router from 'koa-joi-router';
import userRouter from 'userRoutes';
apiRouter.prefix('/app');
apiRouter.route(userRouter.routes);
export default apiRouter;

server.js

import AppApiRouter from 'mainRoutes';
app.use(AppApiRouter.middleware());

So actually, now my userRouter uri should be '/app/user/path'. Instead it is replacing prefix with new prefix string. In mainRoutes.js , apiRouter.route is directly accessing userRoutes.routes object. We are adding prefix as key in router object, that's why mainRouter is not able to get new path.

How to solve this?

paul42 commented 7 years ago

I believe the root cause of your issue is that .prefix() doesn't prepend '/users' to each route, so that when you got to your apiRouter and run apiRouter.route(userRouter.routes); apiRouter doesn't get any information on what userRouter's prefix is. you'd have to request an enhancement (or make a pull request) to perhaps add a method like .compose() where it takes in another router, and adds it together, prefix, routes, and options.

I think if you want a short-term fix, you'd have to mount the userRouter separately, I think in server.js you need a similar entry in your server.js

app.use(userRouter.middleware());
app.use(apiRouter.middleware());

for each router that you want to have a unique prefix on. unless there's a way to have the api be composeable (perhaps other contributors can chime in, I'm just a novice user).

pixeldrew commented 7 years ago

The way i've been able to compose paths is by having the parent route use the child routes as middleware, effectively composing them. YMMV

import router from 'koa-joi-router';
const userRouter = router();
userRouter.prefix('/user');
const userRoutes = [...];
userRouter.route(userRoutes);
export default userRouter;
import router from 'koa-joi-router';
import userRouter from 'userRoutes';
apiRouter.prefix('/app');
apiRouter.use('', userRouter);
export default apiRouter;
thakkaryash94 commented 7 years ago

@pixeldrew that's interesting approach and it is working. Thanks a lot.

pixeldrew commented 7 years ago

My ideal solution is to recursively add files in a directory as a route using the package 'require-directory'. These can either be descriptor literals that are the params to the Router.route method or Router objects themselves, as a rough example:

const Router = require('koa-joi-router');
const routes = require('require-directory')(module, {
  visit: (module) => {
    if (module instanceof Router) {
      return module;
    }
    const router = Router();
    router.route(module);
    return router;
  },
});

const router = Router();
// root url
router.prefix('/app');

const addChildRoute = (path, [key, route]) => {
  if (route instanceof Router) {
    router.use(path, route);
  } else {
    Object.entries(route).forEach(addChildRoute.bind(null, `${path}/${key}`));
  }
};

Object.entries(routes).forEach(addChildRoute.bind(null, ''));
pixeldrew commented 7 years ago

It'd be good to have @aheckmann chime in on whether or not this approach seems valid. When debugging routes i've noticed that koa-router is checking a lot of invalid routes.

aheckmann commented 5 years ago

Closing due to inactivity. Please reopen with a reproducible example if the issue persists.