Отдых с Express.js вложенным маршрутизатором
Предположим, что я хочу иметь конечные точки REST, которые выглядят примерно так:
/user/
/user/user_id
/user/user_id/items/
/user/user_id/items/item_id
CRUD на каждом, если имеет смысл. Например, POST пользователя создает нового пользователя, GET выбирает всех пользователей. /user/user _id GET выбирает только одного пользователя.
Элементы являются специфичными для пользователя, поэтому я помещаю их под user_id, который является конкретным пользователем.
Теперь, чтобы сделать модульную экспресс-маршрутизацию, я сделал несколько экземпляров маршрутизатора. Для пользователя есть маршрутизатор и маршрутизатор для этого элемента.
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-адрес item
- это потомки иерархии URL-адреса user
. Теперь, как мне получить URL с /users
независимо от userRouter, но более конкретный маршрут /user/*user_id*/items/
в itemRouter? Кроме того, я бы хотел, чтобы user_id был доступен для itemRouter, если это возможно.
Ответы
Ответ 1
Вы можете встраивать маршрутизаторы, прикрепляя их как промежуточное программное обеспечение на другом маршрутизаторе, с или без params
.
Вы должны передать {mergeParams: true}
дочернему маршрутизатору, если хотите получить доступ к params
от родительского маршрутизатора.
mergeParams
был введен в Экспресс 4.5.0
(5 июля 2014 г.)
В этом примере 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);
Ответ 2
управляемые вложенные маршруты...
Мне нужен конкретный пример выполнения вложенных маршрутов очень удобным способом в express 4, и это был лучший результат поиска для "вложенных маршрутов в экспресс". Здесь API, который будет иметь много маршрутов, которые нужно будет разбить, например.
./index.js:
var app = require('express')();
// anything beginning with "/api" will go into this
app.use('/api', require('./routes/api'));
app.listen(3000);
<сильные > ./маршруты/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;
<сильные > ./маршруты/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;
Пример размещения в структуре папок
Я заметил некоторые комментарии к "структуре папок вложенности". Это подразумевается в этом, однако не очевидно, поэтому я добавил раздел ниже. Здесь приведен конкретный пример структуры вложенных папок для маршрутов.
index.js
/api
index.js
/admin
index.js
/users
index.js
list.js
/permissions
index.js
list.js
Это более общий пример того, как работает node. Если вы используете "index.js" в папках так же, как "index.html" работает на веб-страницах для каталога по умолчанию, это будет легко масштабировать вашу организацию на основе рекурсии, не изменяя точки входа в код. "index.js" - это документ по умолчанию, доступ к которому при использовании требует в каталоге.
содержимое 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;
Здесь возможно несколько СУХИХ проблем, но он хорошо подходит для инкапсуляции проблем.
FYI, недавно я попал в actionhero и нашел его полнофункциональными w/сокетами и задачами, более похожими на настоящую фреймворк "все в одном", который перевернул парадигму REST на голове. Вероятно, вы должны проверить это, когда будете голыми w/express.
Ответ 3
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"}
Ответ 4
Использование решения @Jason Sebring и адаптация для Typescript.
server.ts
import Routes from './api/routes';
app.use('/api/', Routes);
/api/index.ts
import { Router } from 'express';
import HomeRoutes from './home';
const router = Router();
router.use('/', HomeRoutes);
// add other routes...
export default router;
/api/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;
Ответ 5
Вам нужен только один маршрутизатор и используйте его следующим образом:
router.get('/users');
router.get('/users/:user_id');
router.get('/users/:user_id/items');
router.get('/users/:user_id/items/:item_id');
app.use('api/v1', router);