简体   繁体   English

将版本化 API 路由动态加载到 express.Router

[英]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/ ,这是一个示例路线:

//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.假设还有一个类似的路由文件, cats.js ,为简洁起见,这里省略了。 I'm exporting both modules from index.js :我正在从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 :最后在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?有没有办法将单个路由模块加载到express.Router (我的src/routes/api/index.jsv0 )而无需将每个模块都传递给我? 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.您可以使用fs模块读取文件并导出其功能。 You can look at my code here .你可以在这里查看我的代码。

the __dirname I use was the models dirname.我使用的__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在 OP 编辑​​问题后添加此答案

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. ES6 的import export无法动态确定。 On purpose, ES6 requires static analysis of imports and exports to be possible. ES6 有意要求对导入和导出进行静态分析。 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? 我可以使用循环来最小化 ES6 导入语句吗?

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.如果您使用的是require() ,那么您可以构建一个模块,该模块可以读取配置文件并通过查看文件系统或读取指定所有路由文件的配置文件来加载所有路由文件。 But, you can do that with ES6 import and export .但是,您可以使用 ES6 importexport来做到这一点。 So, as best I know, if you're going to use import and export , you will have to specify the imports manually.因此,据我所知,如果您要使用importexport ,则必须手动指定导入。 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 }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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