Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ExpressJS req.params empty in nested routers

I use a routing setup that uses my 'api' folder's dir structure to intuitively set up the routes. However, in cases where I use a folder name to represent a route parameter, req.params is undefined in the controller.

The route with the problem is:

GET /api/google/accounts/:account_id/analytics/profiles/

Here is my route loader. It basically does a glob on the api folder looking for files named routes.js and does app.use on the appropriate route (determinited from the folder structure).

  // load routers
  files = glob.sync("api/**/routes.js");

  console.log(files);
  // [ 'api/campaigns/routes.js',
  //   'api/google/accounts/:account_id/analytics/profiles/routes.js',
  //   'api/google/accounts/routes.js',
  //   'api/google/urls/routes.js',
  //   'api/users/routes.js' ]

  // use each router on the appropriate route
  for(var i=0;i<files.length;i++) {

    route  = "/" + files[i].split("/routes.js")[0];

    console.log(route);
    // '/api/google/accounts/:account_id/analytics/profiles'

    router = require(path.join(__dirname, files[i]))(config);
    routes = router.stack;
    app.use(route, router);

    // list all registered routes for this router
    for(var j=0;j<routes.length;j++) {
      routeDebug(("      " + Object.keys(routes[j].route.methods)[0].toUpperCase()).slice(-6) + " " + route + routes[j].route.path);
    }
  }

The 'api' folder structure is:

./api
./api/campaigns
./api/campaigns/controller.js
./api/campaigns/model.js
./api/campaigns/routes.js
./api/users
./api/users/controller.js
./api/users/model.js
./api/users/routes.js
./api/google
./api/google/accounts
./api/google/accounts/:account_id
./api/google/accounts/:account_id/analytics
./api/google/accounts/:account_id/analytics/profiles
./api/google/accounts/:account_id/analytics/profiles/controller.js
./api/google/accounts/:account_id/analytics/profiles/routes.js
./api/google/accounts/controller.js
./api/google/accounts/model.js
./api/google/accounts/routes.js
./api/google/urls
./api/google/urls/controller.js
./api/google/urls/routes.js

In the above loop, routeDebug is a wrapper around the debug npm package. Output is:

  routes    GET /api/campaigns/ +0ms
  routes   POST /api/campaigns/ +2ms
  routes    GET /api/campaigns/:campaign_id +1ms
  routes    PUT /api/campaigns/:campaign_id +0ms
  routes DELETE /api/campaigns/:campaign_id +0ms
  routes    GET /api/google/accounts/:account_id/analytics/profiles/ +128ms
  routes    GET /api/google/accounts/ +4ms
  routes   POST /api/google/accounts/ +0ms
  routes   POST /api/google/urls/ +3ms
  routes    GET /api/users/ +12ms
  routes   POST /api/users/ +0ms
  routes    GET /api/users/:user_id +0ms
  routes    PUT /api/users/:user_id +0ms
  routes DELETE /api/users/:user_id +0ms

So we can see that the route in question is being set up as expected. But req.params is undefined. Other routes don't have this problem.

Why is req.params empty only for this particular route? Is there a better way to get these nested routes built than using a folder as a route param?

EDIT: I expect that the issue stems from nested routers not being able to access parent routers' params.

Rest with Express.js nested router

However, setting up the child router as suggested doesn't help either.

var router = require("express").Router({mergeParams: true});
// no difference
like image 459
mz3 Avatar asked Mar 17 '15 15:03

mz3


1 Answers

It turns out mergeParams was not added to Express until 4.5.0; my project was still on 4.2.0. Updating to 4.5.0 and passing {mergeParams: true} to the child router solved the issue. See this similar question for more details:

Rest with Express.js nested router

like image 128
mz3 Avatar answered Oct 22 '22 16:10

mz3