使用 Express.js 嵌套路由器休息

IT技术 javascript node.js express
2021-01-18 10:56:08

假设我想要大致如下所示的 REST 端点:

/user/
/user/user_id 

/user/user_id/items/
/user/user_id/items/item_id

每个 if 的 CRUD 都有意义。例如,/user POST 创建一个新用户,GET 获取所有用户。/user/ user_id GET 只获取那个用户。

项目是用户特定的,所以我把它们放在user_id,这是一个特定的用户。

现在为了使 Express 路由module化,我制作了一些路由器实例。有一个供用户使用的路由器,一个供项目使用的路由器。

var userRouter = require('express').Router();
userRouter.route('/')
  .get(function() {})
  .post(function() {})
userRouter.route('/:user_id')
  .get(function() {})

var itemRouter = require('express').Router();
itemRouter.route('/')
  .get(function() {})
  .post(function() {})
itemRouter.route('/:item_id')
  .get(function() {})

app.use('/users', userRouter);

// Now how to add the next router?
// app.use('/users/', itemRouter);

URL toitem是 的 URL 层次结构的后代user现在我/users如何通过 userRouter获取 URL 以及到 itemRouter 的更具体的路由/user/*user_id*/items/而且,如果可能,我希望 itemRouter 也可以访问 user_id。

6个回答

您可以通过将路由器作为中间件附加到其他路由器上来嵌套路由器,无论是否带有params.

{mergeParams: true}如果params要从父路由器访问,则必须传递给子路由器。

mergeParamsExpress4.5.0中引入(2014 年 7 月 5 日)

在这个例子中,itemRouter被附着在userRouter/:userId/items路线

这将导致以下可能的路线:

GET /user-> hello user
GET /user/5-> hello user 5
GET /user/5/items-> hello items from user 5
GET /user/5/items/6->hello item 6 from user 5

var express = require('express');
var app = express();

var userRouter = express.Router();
// you need to set mergeParams: true on the router,
// if you want to access params from the parent router
var itemRouter = express.Router({mergeParams: true});

// you can nest routers by attaching them as middleware:
userRouter.use('/:userId/items', itemRouter);

userRouter.route('/')
    .get(function (req, res) {
        res.status(200)
            .send('hello users');
    });

userRouter.route('/:userId')
    .get(function (req, res) {
        res.status(200)
            .send('hello user ' + req.params.userId);
    });

itemRouter.route('/')
    .get(function (req, res) {
        res.status(200)
            .send('hello items from user ' + req.params.userId);
    });

itemRouter.route('/:itemId')
    .get(function (req, res) {
        res.status(200)
            .send('hello item ' + req.params.itemId + ' from user ' + req.params.userId);
    });

app.use('/user', userRouter);

app.listen(3003);
如果它们在任何路线上都不可用,我会感到惊讶,因为查询参数与特定的任何路线无关......
2021-03-16 10:56:08
这不再比路由器的“标准”使用更清晰,我正在寻找一种在查看代码时可视化嵌套的方法。
2021-03-17 10:56:08
谢谢你的回答。是否有类似的方法可以从子路由获取父路由查询参数?
2021-03-25 10:56:08
谢谢你的回答。您在此处使用的路由器比 Jordonias 共享的路由器更明确地嵌套。但它在引擎盖下的工作原理是否相同?我想授予你全面性的赏金,但我要到几个小时后才能做到。
2021-03-26 10:56:08
很认真的回答!一个问题:为了封装和分离用户路由器和项目路由器之间的知识,是否有一种声明方式来指定子路由器需要一个参数?换句话说,是否有一种明确的方式来编写注册或访问调用,以便项目路由器让我们知道它希望传递一个用户 ID?示例情况,项目路由器完全在另一个文件中,结构上不清楚它需要用户,除非您进入它的调用,并且只有在用户路由器中才清楚它会传递用户 ID
2021-04-07 10:56:08

可管理的嵌套路由...

我想要一个在 express 4 中以非常易于管理的方式执行嵌套路由的特定示例,这是“express 中的嵌套路由”的最佳搜索结果。例如,这是一个 API,其中包含许多需要分解的路由。

./index.js:

var app = require('express')();

// anything beginning with "/api" will go into this
app.use('/api', require('./routes/api'));

app.listen(3000);

./routes/api/index.js:

var router = require('express').Router();

// split up route handling
router.use('/products', require('./products'));
router.use('/categories', require('./categories'));
// etc.

module.exports = router;

./routes/api/products.js:

var router = require('express').Router();

// api/products
router.get('/', function(req, res) {
  res.json({ products: [] });
});

// api/products/:id
router.get('/:id', function(req, res) {
  res.json({ id: req.params.id });
});

module.exports = router;

文件夹结构中的嵌套示例

我注意到一些关于“嵌套文件夹结构”的评论。这暗示了这一点,但并不明显,所以我添加了下面的部分。这是routes 嵌套文件夹结构的具体示例

index.js
/api
  index.js
  /admin
    index.js
    /users
      index.js
      list.js
    /permissions
      index.js
      list.js

这是节点如何工作的更一般的例子。如果您在文件夹中使用“index.js”类似于“index.html”在网页中为目录默认工作的方式,这将很容易基于递归扩展您的组织,而无需更改您的代码入口点。“index.js”是在目录中使用require时访问的默认文档

index.js 的内容

const express = require('express');
const router = express.Router();
router.use('/api', require('./api'));
module.exports = router;

/api/index.js 的内容

const express = require('express');
const router = express.Router();
router.use('/admin', require('./admin'));
module.exports = router;

/api/admin/index.js 的内容

const express = require('express');
const router = express.Router();
router.use('/users', require('./users'));
router.use('/permissions', require('./permissions'));
module.exports = router;

/api/admin/users/index.js 的内容

const express = require('express');
const router = express.Router();
router.get('/', require('./list'));
module.exports = router;

这里可能存在一些 DRY 问题,但它确实很适合封装关注点。

仅供参考,最近我进入了 actionhero 并发现它具有带套接字和任务的全功能,更像是一个真正的多合一框架,颠覆了 REST 范式。你应该检查一下,而不是用快递裸体。

我看到这如何拆分路由,但它如何解决嵌套问题?
2021-03-18 10:56:08
完美……而且有道理。这是一个可扩展的选项。我很想知道操作将如何实现版本控制(v1、v2 等)
2021-03-30 10:56:08
5 年过去了,看起来还是不错的,谢谢!
2021-04-09 10:56:08
var userRouter = require('express').Router();
var itemRouter = require('express').Router({ mergeParams: true }); 

userRouter.route('/')
  .get(function(req, res) {})
  .post(function(req, res) {})
userRouter.route('/:user_id')
  .get(function() {})

itemRouter.route('/')
  .get(function(req, res) {})
  .post(function(req, res) {})
itemRouter.route('/:item_id')
  .get(function(req, res) {
    return res.send(req.params);
  });

app.use('/user/', userRouter);
app.use('/user/:user_id/item', itemRouter);

问题第二部分的关键是使用 mergeParams 选项

var itemRouter = require('express').Router({ mergeParams: true }); 

/user/jordan/item/cat我得到回应:

{"user_id":"jordan","item_id":"cat"}
凉爽的。你和威廉的方法都适用于我想要的。我会检查他的全面性,但我也会标记你。非常感谢。您的方法看起来不是嵌套的,但它几乎可以满足我的要求,我想我什至更喜欢您的方法。谢谢。
2021-03-27 10:56:08
mergeParams 选项是这里的关键!
2021-03-28 10:56:08

使用 @Jason Sebring 解决方案,并适应 Typescript。

服务器.ts

import Routes from './api/routes';
app.use('/api/', Routes);

/api/routes/index.ts

import { Router } from 'express';
import HomeRoutes from './home';

const router = Router();

router.use('/', HomeRoutes);
// add other routes...

export default router;

/api/routes/home.ts

import { Request, Response, Router } from 'express';

const router = Router();

router.get('/', (req: Request, res: Response) => {
  res.json({
    message: 'Welcome to API',
  });
});

export default router;
@Julian:我已经修复了文件位置。./api/routes有两个文件index.tshome.ts. 第一个被 使用server.ts希望它会帮助你。
2021-03-27 10:56:08
你能提供./api/routes吗?
2021-04-06 10:56:08

尝试将{ mergeParams: true }外观添加 到它的中间件在控制器文件getUser中同时 使用它的简单示例中postUser

const userRouter = require("express").Router({ mergeParams: true });
export default ()=>{
  userRouter
    .route("/")
    .get(getUser)
    .post(postUser);

  userRouter.route("/:user_id").get(function () {});
}