2
\$\begingroup\$

I am trying to build a REST API with express router, which contains of nested sub routes. I have mounted these sub routes in my index.js file.

I have defined it as follows:

// Mounted routes
app.use('/api/v1/Project', new ProjectRouter().routes);
app.use('/api/v1/Project/:projectId/Context', new ContextRouter().routes);
app.use('/api/v1/Project/:projectId/Context/:contextId/Question', new QuestionRouter().routes);
app.use('/api/v1/Project/:projectId/Context/:contextId/Question/:questionId/Answer', new AnswerRouter().routes);

I want to arrange my routes revolved around the functionality and being more complaint towards REST standards.

In the case the route prefix /api/v1/Project/ is being repeated over and over again.

Is there some best practice to minimize the redundant routes by prefixing?

\$\endgroup\$
1
  • 1
    \$\begingroup\$ This may be a little ancillary to what you are saying, but it is a common practice to limit the depth of your routes. restful-api-design.readthedocs.io/en/latest/urls.html For instance, you most likely dont need project and context in the url to modify a question's anwser. \$\endgroup\$
    – unflores
    Commented Nov 26, 2018 at 22:44

2 Answers 2

1
\$\begingroup\$

This is where the Express Router class comes in. You could define a router for ‘api/v1/Project’, mount that router to you main app, and then add the individual routes to the router.

\$\endgroup\$
-1
\$\begingroup\$

The main idea is you can define routes in each controller (no matter how). For hide the base route, you can use a base class with a method addRoute and a property baseRoute or just use a simple variable for base route.

With Ecma6 will look something like this:

in projects.controller.js

require('base.controller.js')
class ProjectsController extends BaseController {
  constructor(app){
    super(app, "/api/v1/Project");
    this.addRoute("/", "get", this.getAll);
    this.addRoute("/:id", "get", this.getOne)
  }
  getAll(){}
  getOne(){}
}
module.exports = ProjectsController;

in 'base.controller.js':

class BaseController {
  constructor(app, baseRoute){
    this.baseRoute = baseRoute;
    this.app = app
  }
  addRoute(route, method, callback){
    const url = this.baseRoute + route;
    console.log('controllerRoute', url, method);
    this.app[method](url, callback.bind(this));
 }
}
module.exports=BaseController;

and in index.js (or app/server.js), for each controller:

require("./projects.controller.")(app);

The simplest way:

let baseRoute = "/api/v1/Project";
app.use(baseRoute + "/", new ProjectRouter().routes);
app.use(baseRoute + '/:projectId/Context', new ContextRouter().routes);
\$\endgroup\$
4
  • 1
    \$\begingroup\$ Kunal isn't using TypeScript, and this setup has multiple issues. 1. Method isn't passed to addRoute. 2. No super() call. 3. No nice way to specify another controller is under /api/v1/Project. 4. Routes are currently looking like /api/api/... \$\endgroup\$
    – Gerrit0
    Commented Dec 3, 2018 at 4:47
  • \$\begingroup\$ Yes you are right. I corrected the mistakes. What do you mean by 3. ? \$\endgroup\$
    – Bogdan
    Commented Dec 3, 2018 at 5:03
  • \$\begingroup\$ You mean is not ok to define a base class for controller? \$\endgroup\$
    – Bogdan
    Commented Dec 3, 2018 at 5:11
  • \$\begingroup\$ About typescript: Ecma6 is very similar with Typescript (except types), so why is this a problem? \$\endgroup\$
    – Bogdan
    Commented Dec 3, 2018 at 5:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.