Express.js नेस्टेड राउटर के साथ आराम करें


136

मान लीजिए कि मैं 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। अब मुझे /usersजो भी userRouter के साथ URL मिलता है, लेकिन आइटम राऊटर का अधिक विशिष्ट मार्ग है /user/*user_id*/items/? और यह भी, मैं चाहूंगा कि user_id आइटमरैटर के लिए भी सुलभ हो, यदि संभव हो तो।


इसे हल करने के लिए एक्सप्रेस का उपयोग करने पर पहले से ही महान जवाब। हालाँकि, आप एक स्वैगर-आधारित एपीआई को लागू करने के लिए लूपबैक (एक्सप्रेस पर निर्मित) का उपयोग कर सकते हैं और सीआरयूडी का प्रदर्शन करने के लिए मॉडल के बीच संबंध जोड़ सकते हैं। प्रारंभिक सीखने की अवस्था के बाद अच्छी बात है, यह इकट्ठा करने के लिए बहुत तेज है। loopback.io
माइक एस।

जवाबों:


278

आप राउटर को किसी अन्य राउटर पर मिडलवेयर के रूप में या उसके साथ संलग्न करके राउटर को घोंसला बना सकते हैं 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);

3
जवाब के लिए धन्यवाद। राउटर जो आप यहां उपयोग करते हैं, वह स्पष्ट रूप से जॉर्डनियों द्वारा साझा किए गए की तुलना में नेस्टेड है। लेकिन क्या यह हुड के नीचे भी काम करता है? मैं आपको समझदारी के लिए इनाम देना चाहता हूं, लेकिन कुछ घंटों बाद तक ऐसा नहीं कर सकता।
ह्यूगी

जवाब के लिए धन्यवाद। क्या शिशु मार्ग से मूल मार्ग के क्वेरी पैरामेट्स प्राप्त करने का एक समान तरीका है ?
cwarny

1
यह मुझे आश्चर्य होगा अगर वे किसी भी मार्ग पर उपलब्ध नहीं हैं, क्योंकि क्वेरी परम विशिष्ट में किसी भी मार्ग से बंधे नहीं हैं ...
विल्म डी'हैसेलेर

बहुत गहन जवाब! एक प्रश्न: उपयोगकर्ता राउटर और आइटम राउटर के बीच ज्ञान के पृथक्करण और पृथक्करण के लिए, यह घोषित करने का एक तरीका है कि एक सबरॉटर को पैरामीटर की आवश्यकता है? दूसरे शब्दों में, क्या पंजीकरण या एक्सेस कॉल लिखने का एक स्पष्ट तरीका है कि आइटम राउटर हमें यह बताता है कि उपयोगकर्ता आईडी पास होने की उम्मीद है? उदाहरण की स्थिति, आइटम राउटर पूरी तरह से किसी अन्य फ़ाइल में है, संरचनात्मक रूप से यह स्पष्ट नहीं है कि इसके लिए एक उपयोगकर्ता की आवश्यकता होती है जब तक कि आप इसकी कॉल में नहीं आते हैं और यह केवल उपयोगकर्ता राउटर में स्पष्ट है कि यह एक यूजर आईडी
yo.ian.g

यह कोई अधिक सुपाठ्य नहीं है कि राउटर्स का "मानक" उपयोग, मैं कोड को देखते समय नेस्टिंग की कल्पना करने का एक तरीका ढूंढ रहा हूं।
DrewInTheMountains 21

127

प्रबंधनीय नेस्टेड मार्ग ...

मैं एक्सप्रेस 4 में बहुत प्रबंधित तरीके से नेस्टेड रूट करने का एक विशिष्ट उदाहरण चाहता था और यह "एक्सप्रेस में नेस्टेड रूट" के लिए शीर्ष खोज परिणाम था। यहां एक एपीआई है जिसमें कई मार्ग होंगे जिन्हें उदाहरण के लिए तोड़ना होगा।

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

फ़ोल्डर संरचना में नेस्टिंग उदाहरण

मैंने "नेस्टिंग फ़ोल्डर संरचना" पर कुछ टिप्पणियां देखीं। यह इसमें निहित है, हालांकि स्पष्ट नहीं है इसलिए मैंने नीचे अनुभाग जोड़ा है। यहां मार्गों के लिए नेस्टेड फ़ोल्डर संरचना का एक विशिष्ट उदाहरण है ।

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

यह नोड कैसे काम करता है इसका एक सामान्य उदाहरण है। यदि आप फ़ोल्डर में "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;

संभवतया यहां कुछ DRY मुद्दे हैं लेकिन यह चिंताओं के एनकैप्सुलेशन के लिए अच्छी तरह से उधार देता है।

FYI करें, हाल ही में मैं एक्शनरियो में आया और पाया कि यह पूर्ण विशेषताओं वाले w / sockets और कार्य हैं, जो एक सच्चे ढांचे की तरह है, जिसमें सभी अपने सिर पर REST प्रतिमान को पलटते हैं। आपको संभवतः नग्न w / एक्सप्रेस पर जाने की जाँच करनी चाहिए।


11
मैं देखता हूं कि यह मार्गों को कैसे विभाजित करता है, लेकिन यह घोंसले के शिकार को कैसे संबोधित करता है?
1252748

परिपूर्ण .... और समझ में आता है। यह एक स्केलेबल विकल्प है। मुझे यह जानने की उत्सुकता होगी कि ऑप संस्करण (v1, v2 आदि) को कैसे लागू करेगा
Kermit_ice_tea

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

आपके प्रश्न के दूसरे भाग की कुंजी मर्जपार्म्स विकल्प का उपयोग है

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

जब से /user/jordan/item/catमुझे एक उत्तर मिलता है:

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

ठंडा। तुम्हारा और विलेम दोनों का तरीका वही है जो मैं चाहता था। मैं उसकी समझ के लिए जाँच करूँगा, लेकिन मैं आपको भी चिन्हित करूँगा। बहुत बहुत धन्यवाद। आपकी विधि नेस्टेड नहीं लगती है, लेकिन यह बहुत अधिक है जो मैं चाहता था कि मुझे लगता है कि मैं भी आपको पसंद करता हूं। धन्यवाद।
हग्गी

मर्जप्रेम विकल्प यहाँ महत्वपूर्ण है!
श्रीमती

2

@ जैसन सेब्रिंग समाधान का उपयोग करना, और टाइपस्क्रिप्ट के लिए आदत डालना।

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;

क्या आप प्रदान कर सकते हैं ./api/routes?
जूलियन

1
@ जूलियन: मैंने फ़ाइल स्थान निर्धारित कर दिए हैं। ./api/routesदो फाइलें index.tsऔर हैं home.ts। पहले एक द्वारा उपयोग किया जाता है server.ts। आशा है इससे आपकी मदद होगी।
पियरे रा

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

आपको केवल एक राउटर की आवश्यकता है, और इसे इस तरह उपयोग करें:

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

हां, लेकिन मैं आइटम और उपयोगकर्ताओं के बीच लॉजिक को अलग करना चाहता हूं, और इसलिए मैं उन्हें अलग करना पसंद करता हूं। मुझे नहीं पता कि क्या यह संभव है।
ह्यूगी

@huggie itemsसे संबंधित usersसही, तुम क्यों कि अलग करने की जरूरत है? यदि आप चाहते हैं कि आप एक ही राउटर का उपयोग करके उन्हें अभी भी अलग-अलग फ़ाइलों में परिभाषित कर सकते हैं।
उदाहरण

यह उपयोगकर्ता का है, लेकिन मैं उपयोगकर्ता को प्रभावित किए बिना इसे आसानी से अंदर या बाहर प्लग करना चाहता हूं। और वर्तमान में मेरे पास एक अलग यूआरएल एंडपॉइंट के लिए प्रत्येक राउटर है। शैली को जनरेटर द्वारा प्रोत्साहित किया गया लगता है। यदि यह संभव नहीं है, तो हाँ शायद मुझे राउटर का उदाहरण अलग-अलग फाइलों में भेजना चाहिए? लेकिन यह मूल संरचनाओं के अनुरूप नहीं है।
ह्यूगी

क्या एक राउटर को दूसरे के नीचे जोड़ना संभव है? चूंकि एक्सप्रेस मिडलवेयर आर्किटेक्चर को रूटर के नीचे से नियंत्रित किया जा रहा है (मुझे पूरी तरह से यकीन नहीं है कि यह है तो) मुझे लगता है कि यह संभव हो सकता है।
ह्यूगी

2
-1 यह उस सवाल का जवाब नहीं दे रहा है जो नेस्टेड राउटर्स के बारे में है
विलेम डी'हैसेलेर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.