GarethL
GarethL

Reputation: 1493

Express Routing - how to require a file containing routes based on a URL Parameter?

I think I'm missing somthing simple...

Simply put, why does this work:

router.use('/:object', require('../v1/routes'));

But this not? [EDITED after Evert's answer, below]

function getRouter(req, res, next) {
    return require('../v1/routes');
}

router.use('/:object', getRouter());

where '../v1/routes' contains simply:

const express = require('express');
const router = express.router({ mergeParams: true });

router.get('/', getAll);

function getAll(req, res, next) {
    res.send("Hello");
}

module.exports = router;

I was hoping to dynamically require the files using the API version as a filesystem base. Further up the chain I get the API version as part of the URL, so I was hoping to use that to drive the directory for the included routing file:

function getRouter(req, res, next) {
    return require(`../${req.params.apiVersion}/routes`);
}

Is there any way to include the router by require-ing its filepath dynamically?

Thanks for any help.

EDIT 1 If I return my function call as I originally had it:

function getRouter(req, res, next) {
    console.log(req.params.apiVersion);
    return require(`../${req.params.apiVersion}/routes`);
}

router.use('/:object', getRouter);

I actually get 'v1' written in the console log; so the parameters are there in fact, but the 'return require'... doesn't seem to be working as I imagined.

EDIT 2 - SOLUTION Thanks to Evert's hints, I eventually got there:

function getRouter(req, res, next) {
    const dynamicRouter = require(`../${req.params.apiVersion}/routes`);
    return dynamicRouter(req, res, next);
}

router.use('/:object', getRouter);

Upvotes: 0

Views: 52

Answers (1)

Evert
Evert

Reputation: 99523

I'll answer just the first portion of this question.

These two are not equivalent:

// #1
router.use('/:object', require('../v1/routes'));

// #2
function getRouter() {
   return require('../v1/routes');
}
router.use('/:object', getRouter);

In the first snippet you are returning the result of require to router.use. In the second you are returning a function that returns the result of getRouter() to router.use.

To make these equivalent, the second one has to look like this:

router.use('/:object', getRouter());

Now we're calling getRouter instead of just passing it.

Overall I think this pattern is really strange though. Especially since you are creating another router in v1/routes. I don't think the top-level router does anything here. Just define this is a general middleware instead.

But, this should at least explain the difference between the first 2 calls.

Upvotes: 1

Related Questions