IT박스

Express.js 중첩 라우터로 휴식

itboxs 2020. 7. 9. 19:31
반응형

Express.js 중첩 라우터로 휴식


대략 다음과 같은 REST 엔드 포인트를 원한다고 가정하십시오.

/user/
/user/user_id 

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

각각의 CRUD는 의미가 있습니다. 예를 들어, / user 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. 이제 /usersuserRouter에 대한 것이지만 itemRouter에 대한보다 구체적인 경로는 /user/*user_id*/items/무엇입니까? 또한 가능한 경우 item_uter에서도 user_id에 액세스 할 수 있기를 바랍니다.


라우터를 사용하거나 사용하지 않고 다른 라우터에 미들웨어 로 연결하여 라우터를 중첩 할 수 있습니다 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);

관리 가능한 중첩 경로 ...

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

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

Nesting example in folder structure

I noticed some comments on "nesting folder structure". It is implied in this however not obvious so I added the section below. Here's a specific example of a nested folder structure for routes.

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

This is more a general example of how node works. If you use "index.js" in folders similarly to how "index.html" works in web pages for a directory default, this will be easy to scale your organization based off of recursion without changing your entry points to code. "index.js" is the default document accessed when using require in a directory.

contents of index.js

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

contents of /api/index.js

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

contents of /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;

contents of /api/admin/users/index.js

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

There is some DRY issues here possibly but it does lend itself well to encapsulation of concerns.

FYI, recently I got into actionhero and have found it to be full featured w/sockets and tasks, more like a true framework all-in-one flipping the REST paradigm on its head. You should probably check it out over going naked w/ express.


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

The key to the second part of your question is the use of the mergeParams option

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

From /user/jordan/item/cat I get a reponse:

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

Using @Jason Sebring solution, and adapting for 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;

You need only one router, and use it like this:

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

참고URL : https://stackoverflow.com/questions/25260818/rest-with-express-js-nested-router

반응형