web-dev-qa-db-fra.com

Reste avec le routeur imbriqué Express.js

Supposons que je veuille avoir REST points finaux qui ressemblent à peu près à ceci:

/user/
/user/user_id 

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

CRUD sur chaque si a du sens. Par exemple,/user POST crée un nouvel utilisateur, GET extrait tous les utilisateurs./user/ser_id GET ne récupère que cet utilisateur.

Les éléments sont spécifiques à l'utilisateur, donc je les mets sous ser_id, qui est un utilisateur particulier.

Maintenant, pour rendre le routage Express modulaire, j'ai créé quelques instances de routeur. Il existe un routeur pour l'utilisateur et un routeur pour l'élément.

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);

L'URL de item est issue de la hiérarchie des URL de user. Maintenant, comment obtenir l'URL avec /users quel que soit l'utilisateur, mais la route plus spécifique de /user/*user_id*/items/ vers itemRouter? Et aussi, j'aimerais que user_id soit aussi accessible à itemRouter, si possible.

119
huggie

Vous pouvez imbriquer des routeurs en les connectant comme middleware sur un autre routeur, avec ou sans params.

Vous devez transmettre {mergeParams: true} au routeur enfant si vous souhaitez accéder au params à partir du routeur parent.

mergeParams a été introduit dans Express 4.5.0 (5 juillet 2014)

Dans cet exemple, la itemRouter est attachée à la userRouter de la route /:userId/items.

Cela se traduira par les itinéraires possibles suivants:

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);
237
Willem D'Haeseleer

itinéraires imbriqués gérables ...

Je voulais un exemple spécifique de création de routes imbriquées de manière très gérable dans Express 4. Il s’agissait du premier résultat de la recherche pour "routes imbriquées dans express". Voici une API qui aurait plusieurs routes à scinder, par exemple.

./ 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;

Exemple d'imbrication dans la structure de dossiers

J'ai remarqué des commentaires sur la "structure de dossiers". C'est implicite dans ceci cependant pas évident ainsi j'ai ajouté la section ci-dessous. Voici un exemple spécifique de structure de dossiers imbriqués pour les itinéraires.

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

Ceci est plus un exemple général du fonctionnement du noeud. Si vous utilisez "index.js" dans les dossiers de la même manière que "index.html" dans les pages Web pour un répertoire par défaut, il sera facile de faire évoluer votre organisation en fonction de la récursivité sans modifier vos points d'entrée en code. "index.js" est le document utilisé par défaut lors de l'utilisation de requis dans un répertoire.

contenu de index.js

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

contenu de /api/index.js

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

contenu de /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;

contenu de /api/admin/users/index.js

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

Il existe peut-être quelques problèmes DRY ici, mais cela se prête bien à l'encapsulation des préoccupations.

Pour votre information, je me suis récemment lancé dans l'actionhero et je l'ai trouvé complet en fonctions de sockets et de tâches, plus comme un véritable framework tout en renversant le paradigme REST. Vous devriez probablement y jeter un coup d'œil en allant nu avec w/express.

112
Jason Sebring
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);

La clé de la deuxième partie de votre question concerne l'utilisation de l'option mergeParams.

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

De /user/jordan/item/cat je reçois une réponse:

{"user_id":"jordan","item_id":"cat"}
7
Jordonias

Utilisation de la solution @Jason Sebring et adaptation à TypeScript.

server.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;
0
Pierre R-A