Express.js iç içe yönlendiriciyle dinlenme


137

Kabaca şöyle görünen REST uç noktalarına sahip olmak istiyorum:

/user/
/user/user_id 

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

Her biri için CRUD mantıklı. Örneğin, / user POST yeni bir kullanıcı oluşturur, GET tüm kullanıcıları getirir. / user / user_id GET yalnızca bir kullanıcıyı getirir.

Öğeler kullanıcıya özgüdür, bu yüzden onları belirli bir kullanıcı olan user_id altına koyarım .

Şimdi Express yönlendirmeyi modüler yapmak için birkaç yönlendirici örneği yaptım. Kullanıcı için bir yönlendirici ve öğe için bir yönlendirici vardır.

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'sinin URL hiyerarşisinin soyundan gelir user. Şimdi /usersuserRouter'a ne olursa olsun URL'yi nasıl alabilirim, ancak itemRouter'a daha spesifik bir yol /user/*user_id*/items/alabilirim? Ayrıca, mümkünse user_id öğesinin itemRouter tarafından da erişilebilir olmasını istiyorum.


Bunu çözmek için Express'i kullanırken zaten harika yanıtlar. Ancak, Swagger tabanlı bir API uygulamak için Loopback'i (yerleşik Express üzerinde) kullanabilir ve CRUD'yi istediğiniz gibi gerçekleştirmek için modeller arasında ilişkiler ekleyebilirsiniz. İlk öğrenme eğrisinden sonra güzel bir şey, montajı çok daha hızlı. loopback.io
Mike

Yanıtlar:


279

Yönlendiricileri, başka bir yönlendiriciye veya ara sunucuya ara katman yazılımı olarak ekleyerek iç içe yerleştirebilirsinizparams .

Sen geçmelidir {mergeParams: true}erişmek istediğiniz takdirde, çocuk yönlendiriciye paramsana yönlendiriciden.

mergeParamsExpress'te4.5.0 tanıtıldı (5 Tem 2014)

Bu örnekte itemRouterekli alır userRouterüzerinde /:userId/itemsrota

Bu, aşağıdaki olası rotalarla sonuçlanacaktır:

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

3
Cevap için teşekkürler. Burada kullandığınız yönlendirici, Jordonias tarafından paylaşılandan daha açık bir şekilde yuvalanmıştır. Ama kaputun altında da aynı şekilde çalışıyor mu? Size kapsamlılık için lütuf vermek istiyorum, ancak birkaç saat sonrasına kadar yapamam.
huggie

Cevap için teşekkürler. Çocuk yolundan ana yolun sorgu parametrelerini almanın benzer bir yolu var mı ?
cwarny

1
Sorgu parametresi belirli bir rotaya bağlı olmadığından herhangi bir rotada
bulunamazlarsa beni şaşırtacaktır

Çok kapsamlı bir cevap! Bir soru: kullanıcı yönlendiricisi ile öğe yönlendiricisi arasında kapsülleme ve bilgi ayrımı uğruna, bir alt yönlendiricinin parametre gerektirdiğini belirtmenin bildirici bir yolu var mı? Başka bir deyişle, öğe yönlendiricinin bir kullanıcı kimliğinden geçmesini beklediğini bize bildireceği şekilde kayıt veya erişim çağrılarını yazmanın açık bir yolu var mı? Örnek durum, öğe yönlendiricisi tamamen başka bir dosyadadır, yapısal olarak, çağrılarına girmedikçe bir kullanıcı gerektirdiği açık değildir ve sadece kullanıcı yönlendiricisinde bir kullanıcı kimliğini geçeceği
açıktır

Bu yönlendirici "standart" kullanımı artık okunaklı değil, ben kodu görüntülerken iç içe görselleştirmek için bir yol arıyorum.
DrewInTheMountains

127

yönetilebilir iç içe yollar ...

Ekspres 4'te çok yönetilebilir bir şekilde iç içe yollar yapmak için belirli bir örnek istedim ve bu "ekspres iç içe yollar" için en iyi arama sonucu oldu. Örneğin, parçalanması gereken birçok rotaya sahip olacak bir 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;

Klasör yapısında yuvalama örneği

"Klasör yapısı iç içe" hakkında bazı yorumlar fark ettim. Ancak bu açık değildir, bu yüzden aşağıdaki bölümü ekledim. İşte yollar için iç içe klasör yapısının özel bir örneği .

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

Bu, düğümün nasıl çalıştığına dair genel bir örnektir. Bir dizin varsayılanı için "index.html" web sayfalarında nasıl çalıştığına benzer klasörlerde "index.js" kullanırsanız, giriş noktalarınızı koda dönüştürmeden kuruluşunuzu özyineleme temelinde ölçeklendirmek kolay olacaktır. "index.js", bir dizinde gereksinim kullanılırken erişilen varsayılan belgedir .

index.js içeriği

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

/api/index.js içeriği

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

/api/admin/index.js içeriği

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 içeriği

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

Muhtemelen burada bazı KURU sorunlar vardır, ancak endişelerin kapsüllenmesine iyi bir katkıda bulunur.

FYI, son zamanlarda aksiyon kahramanına girdim ve tam özellikli soketler ve görevler olarak buldum, daha çok gerçek bir çerçeve gibi hepsi bir arada REST paradigmasını kafasına çevirdi. Muhtemelen çıplak w / express üzerinden kontrol etmelisiniz.


11
Bunun rotaları nasıl böldüğünü görüyorum, ancak yuvalamayı nasıl ele alıyor?
1252748

mükemmel .... ve mantıklı. Bu ölçeklenebilir bir seçenektir.
Operasyonun

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

Sorunuzun ikinci bölümünün anahtarı, mergeParams seçeneğinin kullanılmasıdır

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

Dan /user/jordan/item/catI Bir tepkisini daha olsun:

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

Güzel. Hem senin hem de Willem'in yöntemi istediğim şey için çalışıyor. Onun kapsamlı olup olmadığını kontrol edeceğim ama sizi de işaretleyeceğim. Çok teşekkürler. Metodunuz iç içe görünmüyor ama istediğim şeyi yapıyor, sanırım sizinkini bile tercih ediyorum. Teşekkürler.
huggie

mergeParams seçeneği burada anahtar!
Şubat'ta MrE

2

@Jason Sebring çözümünü kullanma ve Typescript için uyarlama.

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;

Sağlayabilir misiniz ./api/routes?
Julian

1
@Julian: Dosya konumlarını düzelttim. ./api/routesiki dosyaya sahiptir index.tsve home.ts. İlki tarafından kullanılır server.ts. Umarım size yardımcı olur.
Pierre RA

0
try to add  { mergeParams: true } look to simple example  which it middlware use it in controller file getUser at the same for  postUser
    const userRouter = require("express").Router({ mergeParams: true });
    export default ()=>{
    userRouter
      .route("/")
      .get(getUser)
      .post(postUser);
    userRouter.route("/:user_id").get(function () {});
    
    
    }

-9

Yalnızca bir yönlendiriciye ihtiyacınız var ve bunu şu şekilde kullanın:

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

Evet, ancak mantığı öğeler ve kullanıcılar arasında ayırmak istiyorum ve bu yüzden onları ayırmayı tercih ediyorum. Mümkün olup olmadığını bilmiyorum.
huggie

@huggie sağa itemsaittir users, neden ayırmanız gerekiyor? isterseniz bunları aynı yönlendiriciyi kullanarak farklı dosyalarda tanımlayabilirsiniz.
eguneys

Kullanıcıya ait ancak kullanıcıyı etkilemeden kolayca takıp çıkartabilmek istiyorum. Ve şu anda farklı bir URL uç noktaları için her yönlendiricim var. Stil, ekspres üreteci tarafından teşvik ediliyor gibi görünüyor. Mümkün değilse, evet belki yönlendirici örneğini farklı dosyalara göndermeliyim? Ama bu orijinal yapılarla tutarlı değil.
huggie

Bir yönlendiriciyi diğerinin altına eklemek mümkün müdür? Express ara katman yazılımı mimarisi altında yönlendirici tarafından ele alındığı için (tamamen olup olmadığından emin değilim) mümkün olabileceğini düşünüyorum.
huggie

2
-1 Bu, iç içe yönlendiricilerle ilgili soruyu cevaplamıyor
Willem D'Haeseleer
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.