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?

Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Nov 22, 2018 at 10:58
\$\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\$ 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.

answered Jan 29, 2019 at 2:43
\$\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);
answered Dec 2, 2018 at 12:02
\$\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\$ Commented Dec 3, 2018 at 4:47
  • \$\begingroup\$ Yes you are right. I corrected the mistakes. What do you mean by 3. ? \$\endgroup\$ Commented Dec 3, 2018 at 5:03
  • \$\begingroup\$ You mean is not ok to define a base class for controller? \$\endgroup\$ 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\$ Commented Dec 3, 2018 at 5:15

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.