简体   繁体   中英

Dynamically load versioned API routes into express.Router

My routes live in ./src/routes/api/v0/ , here's an example route:

//src/routes/api/v0/dogs.js
import { Router } from 'express'

const router = Router()

router.get('/dogs', (req, res) => {
  res.json({ message: 'List of all dogs' })
})

router.post('/dogs', (req, res) => {
  res.json({ message: `Created a dog: ${req.body}` })
})

router.put('/dogs/:id', (req, res) => {
  const { id } = req.params
  res.json({ message: `Dog ${id} mutated into ${req.body}` })
})

router.delete('/dogs/:id', (req, res) => {
  const { id } = req.params
  res.json({ message: `Dog ${id} is gone` })
})

export { router as dogs }

Assume that there is a another similar file with routes, cats.js , omitted here for brevity. I'm exporting both modules from index.js :

//src/routes/api/v0/index.js
export * from './cats'
export * from './dogs'

Then, I'm loading them via intermediary, like this:

//src/routes/api/index.js
import { Router } from 'express'
import { cats, dogs } from './v0'
const v0 = Router()

v0.use('/v0', cats)
v0.use('/v0', dogs)

export { v0 }

And finally loading them in server.js :

//src/server.js
import v0 from './routes/api'
...
app.use('/api', v0)
...

Is there a way to load individual route modules into express.Router (the v0 in my src/routes/api/index.js ) without passing every single module my hand? Something like:

//src/routes/api/index.js
import { Router } from 'express'
import * as apiV0 from './v0'

const v0 = Router()

v0.use('/v0', magically feed it apiV0)

You can use fs module to read a file and export its functions. You can look at my code here .

the __dirname I use was the models dirname. then you can use this magic one line require on start of your app.

import initFunction from 'src/routes'
import { Router } from 'express'

initFunction(Router()) // dont forget your express instance

initFunction

One option would be to export an array of routers, rather than naming each one. Then, you can just iterate through that array to add them all in a generic way. So, instead of importing each by name like you do here:

//src/routes/api/index.js
import { Router } from 'express'
import { cats, dogs } from './v0'
const v0 = Router()

v0.use('/v0', cats)
v0.use('/v0', dogs)

export { v0 }

You could export and then import an array of routers and then iterate the array:

//src/routes/api/index.js
import { Router } from 'express'
import { allRouters } from './v0'
const v0 = Router()

for (const router of allRouters) {
    v0.use('/v0', router)
}

export { v0 }

In fact, you could export both the individual named routers like you have now and the array of routers if you wanted and then the importing code would be free to use either individual named routers or the whole array.


Addition to this answer after OP edited the question

Your edit to the question that shows this:

//src/routes/api/v0/index.js
export * from './cats'
export * from './dogs'

creates some complications for any sort of automatic collection of all these routes. ES6 import and export can not be dynamically determined. On purpose, ES6 requires static analysis of imports and exports to be possible. So, you can't import or export in a loop of code. Here's a discussion of that topic:

Can I use loops to minimize ES6 import statements?

If you were using require() , then you could build a single module that could just either read a config file and load all your route files by looking in the file system or by reading a config file that specifies them all. But, you can do that with ES6 import and export . So, as best I know, if you're going to use import and export , you will have to specify the imports manually. By putting them in an array before exporting the collection of routes, you will at least only have to do the manual declaration once instead of twice (which is an improvement over your current code).

Here's importing them manually, but then exporting them in the array which can more easily be processed:

//src/routes/api/v0/index.js
import {dogs} from './dogs'
import {cats} from './cats'

export const allRouters = [dogs, cats];

Then, you could install them:

//src/routes/api/index.js
import { Router } from 'express'
import { allRouters } from './v0'
const v0 = Router()

for (const router of allRouters) {
    v0.use('/v0', router)
}

export { v0 }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM