ExpressJS:在运行时动态添加路由

Doo*_*dle 5 javascript node.js express dynamic-routing

我希望能够在运行时添加新路由,而无需使用 NodeJS 和 ExpressJS 重新启动服务器。我采用了类似的方法,如本文中所示: https: //alexanderzeitler.com/articles/expressjs-dynamic-runtime-routing/
从技术上讲,我可以在本文中同样在运行时添加新文件和逻辑,但问题是当没有 api 路由匹配时,我将发送 404 JSON 响应(正如它应该的那样)。

我认为我遇到的问题是我的动态创建的路由永远不会到达,因为静态路由优先于动态创建的路由。这意味着创建的路由将在错误处理后安装,因此永远不会到达。我在app.js中的代码

...

// Routes
app.use('/api/products', productRoutes);
app.use('/api/users', userRoutes);

...

/* This is where the dynamically created routes should be mounted */

// Error handling
app.use((req, res, next) => {
    const err = new Error('Not found');
    err.status = 404;
    next(err);
});

app.use((err, req, res, next) => {
    res.status(err.status || 500).json({error: {message: err.message}});
});

/* This is where the dynamic routes are mounted */

module.exports = app;
Run Code Online (Sandbox Code Playgroud)

当我注释掉错误处理时,我能够访问在运行时创建的路由,而通过错误处理,我只能在服务器重新启动后访问动态创建的路由,这是我想避免的。
该问题无法通过查询参数解决,因为动态添加的路由在逻辑、模型属性、http 方法/动词和 API 端点方面有所不同。例如
GET/POST /api/{endpoint}
GET/POST /api/foo/{endpoint}
GET/PUT/DELETE /api/foo/bar/{endpoint}/:id

我想我基本上需要:
1)找到在错误处理之前安装动态创建的路由的方法 - 我目前陷入困境或
2)修改路由堆栈 - 我读过这是不切实际的,缓慢的,不好的做法并且容易出错
3)找到

我希望的替代解决方案有人可以帮助我。
提前致谢

编辑
这是创建新路线的代码。相关端点是POST方法中的/api/databases/

const Database = require('../models/database');
const controller = require('./template/controller');
const creation = require('../Creation');

...

exports.createOne = (req, res, next) => {
  if (!creation.findFileInDirectory(`./backend/api/models/${req.body.name.singular}.js`) ||
      !creation.findFileInDirectory(`./backend/api/controllers/${req.body.name.singular}.js`) ||
      !creation.findFileInDirectory(`./backend/api/routes/${req.body.name.singular}.js`)) {
    controller.createOne(req, res, next, Database, {
      modelName: 'database',
    }, () => {
      //creation.createEndpoint(req.body.name, req.body.data, req.body.auth);
      creation.createEndpoint(req.body.name, req.body, req.body.auth);
    });
  } else {
    res.status(422).json({message: 'Endpoint exists already'});
  }
}

...
Run Code Online (Sandbox Code Playgroud)

代码片段中的控制器只是一个模块化控制器文件,它处理我对不同模型的所有端点的所有 CRUD 操作。每条路线都分为模型、控制器和路线,以分离并更好地维护其逻辑。

在 POST 方法中,我首先检查要创建的端点是否已存在。如果是,我会回复 422 来响应端点已存在。如果它不存在,我会在数据库端点中使用我的模块化控制器创建一个条目,并为应该创建的端点创建一个模型、控制器和路由。

创建逻辑如下:

const createEndpoint = (name, data, auth) => {
    createFile(`./backend/api/models/${name.singular}.js`, model.createModel(capitalize(name.singular), data), () => {
      createFile(`./backend/api/controllers/${name.singular}.js`, controller.createController({singular: capitalize(name.singular), plural: name.plural}, data.data), () => {
        createFile(`./backend/api/routes/${name.singular}.js`, route.createRoute({singular: capitalize(name.singular), plural: name.plural}, auth), () => {
          const app = require('../../app');
          mountEndpoints(name.singular, app);
        });
      });
    });
};
Run Code Online (Sandbox Code Playgroud)

在这里,我基本上将数据从 POST 方法传递到异步创建的模型、控制器和路由文件。创建所有文件后,我将端点路由安装到应用程序。挂载路由的逻辑是:

const mountEndpoints = (path, app) => {
  const module = require(`../routes/${path}`);
  app.use(`/api/${module.plural ? `${module.plural}` : `${path}s`}`, module);
}
Run Code Online (Sandbox Code Playgroud)

创建的路线可能如下所示:

const express   = require('express');
const router    = express.Router();
const checkAuth = require('../middleware/check-auth');

const ProductController = require('../controllers/product');

router.route('/')
    .get(ProductController.getAll)
    .post(checkAuth, ProductController.createOne);

router.route('/:id')
    .get(ProductController.getOne)
    .patch(checkAuth, ProductController.patchOne)
    .delete(checkAuth, ProductController.deleteOne);

module.exports = router;
module.exports.plural = 'products';
Run Code Online (Sandbox Code Playgroud)

checkAuth 包含一些授权/身份验证的逻辑。

该代码几乎完成了我想要它做的事情,只是我不知道如何在错误处理之前处理路线的定位。

Mat*_*att 10

快速路线将按创建顺序处理。

要在定义后的特定位置添加路由,app您可以创建占位符路由器并将路由附加到该路由,而不是修改其app本身。

Express 不支持在定义路由后将其删除,但您可以替换整个路由器

创建一个快速路由器实例(或者app如果需要的话甚至另一个)来安装动态端点。每当您想要更改路由时,请重新定义路由器(除了 Express 支持的路由器堆栈末尾的添加之外)。

// Routes
app.use('/api/products', productRoutes);
app.use('/api/users', userRoutes);

let dynamicApiRouter = null

export function setupDynamicRouter(route_configs) {
  dynamicApiRouter = new express.Router()
  // Add routes to dynamicApiRouter from `route_configs`
  for (const config of route_configs) {
    dynamicApiRouter[config.method](config.path, config.handler)
  }
}

app.use('/api', (req, res, next) => dynamicApiRouter(req, res, next))

// Error handling
app.use((req, res, next) => {
    const err = new Error('Not found');
    err.status = 404;
    next(err);
});

app.use((err, req, res, next) => {
    res.status(err.status || 500).json({error: {message: err.message}});
});
Run Code Online (Sandbox Code Playgroud)

setupDynamicRouter()可以随时调用一个或一组路由和处理程序来设置:

const route_config = [
  {
    method: 'get',
    path: '/sales',
    handler: (req, res, next) => res.json({ ok: true }),
  },
  {
    method: 'post',
    path: '/sales',
    handler: (req, res, next) => res.json({ post: true }),
  },
])
setupDynamicRouter(route_config)
Run Code Online (Sandbox Code Playgroud)

对于问题示例“路由”设置,/api路径前缀现在位于父级中的路由器安装上app,因此可以从每个路由中删除router.use

const mountEndpoints = (path, router) => {
  const module = require(`../routes/${path}`);
  router.use(`/${module.plural ? `${module.plural}` : `${path}s`}`, module);
}
Run Code Online (Sandbox Code Playgroud)