tp5.1路由简化_快速路由的简化技术

tp5.1路由简化

A technique to dynamically configure routes for an API built using frameworks such as Express or Fastify

为使用Express或Fastify等框架构建的API动态配置路由的技术

This tutorial will focus on one of my favorite techniques for structuring the route files. This approach uses the folder and file structure to build the API.

Ť他的教程将专注于我最喜欢的技术结构的路径的文件之一。 这种方法使用文件夹和文件结构来构建API。

我们在建什么? (What are we building?)

Following in the footsteps of all great tutorials, we will build a todo list API. This will provide the following endpoints.

遵循所有出色教程的脚步,我们将构建一个待办事项列表API。 这将提供以下端点。

  • GET /todo-item (Returns all todo items)

    GET / todo-item(返回所有待办事项)

  • CREATE /todo-item (Adds a new todo item)

    创建/ todo-item(添加新的待办事项)

  • GET /todo-item[id] (returns the todo item with the id)

    GET / todo-item [id](返回带有ID的待办事项)

  • UPDATE /todo-item/[id] (updates a todo item with the id)

    UPDATE / todo-item / [id](使用ID更新待办事项)

  • DELETE /todo-item/[id] (deletes the item with the id)

    删除/ todo-item / [id](删除带有ID的项目)

A todo item will have the below structure.

待办事项将具有以下结构。

  • id (string — unique id)

    id(字符串-唯一ID)
  • title (string — title of the todo item)

    标题(字符串-待办事项的标题)
  • status (boolean —if the todo item is completed)

    状态(布尔值-如果待办事项已完成)

N

ñ

基本设定 (Basic setup)

Before we proceed, lets set up an API we can play around with.

在继续之前,让我们设置一个我们可以使用的API。

Run the following commands to make a directory and cd into it.

运行以下命令以创建目录并进入该目录。

mkdir dynamic-routes
cd dynamic-routes

Next, run the following to initiate an npm project (the “-y” flag tells it to use default values)

接下来,运行以下命令以启动一个npm项目(“ -y”标志告诉它使用默认值)

npm init -y 

Run the following command to install all the required packages

运行以下命令以安装所有必需的软件包

npm i express body-parser express-promise-router 

Install nodemon using the below command. This will restart the server whenever a file is changed. (The “-D” flag installs it as a dev dependency)

使用以下命令安装nodemon。 每当更改文件时,这将重新启动服务器。 (“ -D”标志将其安装为开发依赖项)

npm i -D nodemon

Next, make an “src” folder for all of our code and add an index.js file inside.

接下来,为我们所有的代码创建一个“ src”文件夹,并在其中添加一个index.js文件。

mkdir src && touch src/index.js

Next, update the package.json file with the following. This main will tell npm where to find our entry file. and secondly, the scripts will provide us with a way to run nodemon.

接下来,使用以下命令更新package.json文件。 该主体将告诉npm在哪里找到我们的入口文件。 其次,这些脚本将为我们提供一种运行nodemon的方法。

{... "main": "src/index.js", // update this line"scripts": {"start": "nodemon" // add this to the scripts},...}

Finally, add the following content in index.js.

最后,在index.js中添加以下内容。

const port = 3000;


const express = require('express');
const { json } = require('body-parser');
const app = express();


app.use(json());
app.get(`/healthcheck`, (req, res) => res.sendStatus(200));


app.listen(port, () => console.log(`api is running on ${port}`));

Now, you can start the script by running the following

现在,您可以通过运行以下命令来启动脚本

npm start

if you go to a browser and access this http://localhost:3000/healthcheck. You should see the following message: OK.

如果您使用浏览器并访问此http:// localhost:3000 / healthcheck 。 您应该看到以下消息:确定。

待办事项项目控制器 (Todo Item Controller)

Another thing we need to code before we proceed is the actual todo controller. This is what the routes will execute to carry out operations.

在继续之前,我们需要编码的另一件事是实际的todo控制器。 这就是路线将执行的操作。

const items = [
  {
    id: '1',
    title: 'hello world',
    status: false,
  },
  {
    id: '2',
    title: 'dynamic routes',
    status: true,
  },
];


function readAll() {
  return items;
}


function createItem(item) {
  if (readItem(item.id)) {
    throw new Error(`item with id: ${item.id} already exists`);
  }


  items.push(item);
}


function readItem(id) {
  return items.find((item) => item.id === id);
}


function updateItem(id, newItem) {
  const index = items.findIndex((item) => item.id === id);


  if (index === -1) {
    throw new Error(`item with id: ${item.id} doesn't exists`);
  }


  items[index] = newItem;


  return newItem;
}


function deleteItem(id) {
  const index = items.findIndex((item) => item.id === id);


  if (index === -1) {
    throw new Error(`item with id: ${item.id} doesn't exists`);
  }


  items.splice(index, 1);
}


module.exports = {
  readAll,
  createItem,
  readItem,
  updateItem,
  deleteItem,
};

Again, this is a super simplified version of the controller, it simply provides a set of functions for manipulating the state of an array.

同样,这是控制器的超级简化版本,它仅提供了一组用于操纵数组状态的函数。

make a controllers folder inside the src, and place this file there. Your folders should look something like below.

在src内创建一个controllers文件夹,然后将此文件放在此处。 您的文件夹应如下所示。

Image for post
todo-item controller
待办事项控制器

怎么做的?(How it’s done?)

The most widely used method for setting up routes is to have a single file that will set up the routers. For a larger project, this file may require all the route handler and link it to the router instance.

设置路由最广泛使用的方法是使用一个文件来设置路由器。 对于较大的项目,此文件可能需要所有路由处理程序并将其链接到路由器实例。

In our example, we have added the handlers in the same file as well.

在我们的示例中,我们也将处理程序添加到了同一文件中。

const Router = require('express-promise-router');
const controller = require('../controllers/todo-item');


module.exports = () => {
  const router = Router();


  router.get('/todo-item/', (req, res) => res.json(controller.readAll()));


  router.post('/todo-item/', (req, res) =>
    res.json(controller.createItem(req.body))
  );
  router.get('/todo-item/:id', (req, res) => {
    return res.json(controller.readItem(req.params.id));
  });
  router.put('/todo-item/:id', (req, res) =>
    res.json(controller.updateItem(req.params.id, req.body))
  );
  router.delete('/todo-item/:id', (req, res) =>
    res.json(controller.deleteItem(req.params.id))
  );


  return router;
};

As you can imagine, this can easily become massive. even if you segregate the functions into their own files, or combine all handlers for one route, they can quickly become spread all over the application.

您可以想象,这很容易变得庞大。 即使您将功能分离到它们自己的文件中,或将所有处理程序合并到一个路由中,它们也可以Swift散布到整个应用程序中。

make a routes folder inside the src, and place this file there. Your folders should look something like below.

在src内创建一个routes文件夹,然后将此文件放在此处。 您的文件夹应如下所示。

Image for post

To be able to hit these endpoints, update your root index.js file with the following lines.

为了能够达到这些端点,请使用以下几行更新您的根index.js文件。

const routes = require('./routes');app.use('/routes', routes());

This will add all the routes we have configured after /routes

这将添加我们在/ routes之后配置的所有路由

Image for post
root index.js file
根index.js文件

我们将如何做?(How we will do it?)

Let's explore the technique of dynamically building the routes based on the folder structure.

让我们探索基于文件夹结构动态构建路由的技术。

For this, first install the following dependency

为此,请首先安装以下依赖项

npm i klaw-sync
  • klaw-sync: a Node.js recursive and fast file system walker

    klaw-sync :Node.js递归和快速文件系统遍历器

next, make a folder called dynamic-routes, and an index.js file inside that.

接下来,创建一个名为dynamic-routes的文件夹,并在其中创建一个index.js文件。

mkdir src/dynamic-routes
touch src/dynamic-routes/index.js

and add the following content in it.

并在其中添加以下内容。

const Router = require('express-promise-router');


const klawSync = require('klaw-sync');
const join = require('path').join;
const BASE_ROUTE = join(__dirname, 'base');


function processPath(path, route) {
  // we remove the base path which will give us the full route
  let endpointPath = path.replace(BASE_ROUTE, '').slice(0, -3); // -3 to account for .js
  let requestType = route.requestType; // default to get


  const requestTypeMatch = endpointPath.match(/\.(.*$)/);


  // prioritize the request type specified in the actual route
  if (!requestType && requestTypeMatch && requestTypeMatch[1]) {
    // if the request type is specified in the path, then we need to remove it from endpoint path
    requestType = requestTypeMatch && requestTypeMatch[1];
    endpointPath = endpointPath.slice(0, -requestType.length - 1); // -1 to account for the .
  }


  if (endpointPath.match(/\/index$/)) {
    endpointPath = endpointPath.replace(/\/index$/, ''); // if the file name has index, then we use the root and remove it
  }


  return { endpointPath, requestType };
}


module.exports = () => {
  const router = Router();


  /**
   * @description Bootstrapping app routes in base folder
   *              This will loop through all .js files in the base folder,
   *              add a route to the routed using the requestType at the given endpoint,
   *              and set the function called endpoint as the listener
   */
  klawSync(BASE_ROUTE, { nodir: true })
    .filter((file) => ~file.path.indexOf('.js'))
    .forEach(({ path }) => {
      const file = path.replace(BASE_ROUTE, '');


      try {
        const route = require(path);


        const { endpointPath, requestType } = processPath(path, route);


        const endpointHandler = route.endpointHandler;


        // check if any middlewares are present
        const handlers = route.middlewares
          ? [...route.middlewares, endpointHandler]
          : endpointHandler;


        router.route(`${endpointPath}`)[requestType](handlers);
        console.info(
          `successfully bootstrapped route: ${requestType} ${endpointPath}`
        );
      } catch (err) {
        console.error(`Error bootstrapping route:  ${file} ->  ${err}`);
      }
    });


  return router;
};

The technique we will use to build the routes dynamically is by starting from a base folder, we will load all files ending in “.js” extension and using the file name, set up the route.

动态构建路由的技术是从基本文件夹开始,然后加载所有以“ .js”扩展名结尾的文件,并使用文件名来设置路由。

路由文件 (Route files)

Each route file should be named in this format.

每个路由文件都应以这种格式命名。

[ROUTE].[REQUEST_TYPE].js
  • ROUTE: the path of the endpoint

    ROUTE:端点的路径
  • REQUEST_TYPE: optional request type (GET/POST)

    REQUEST_TYPE:可选请求类型(GET / POST)

Each route file should expose the following

每个路由文件应公开以下内容

  • endpointHandler (the function handling the request)

    endpointHandler(处理请求的函数)
  • middlewares (optional — array of middlewares to add to the route)

    中间件(可选-添加到路由的中间件数组)
  • requestType (optional —prioritize this request type over the one in the filename)

    requestType(可选-优先于文件名中的该请求类型)
  • endpointPath (optional — prioritize this path over the one in the filename)

    endpointPath(可选-优先于文件名中的路径)
const controller = require('../../../controllers/todo-item');


function endpointHandler(req, res) {
  return res.json(controller.readAll());
}


module.exports = {
  endpointHandler,
};

(Example)

If we had the following folder structure.

如果我们具有以下文件夹结构。

Image for post

This will build all the routes we defined initially.

这将构建我们最初定义的所有路由。

Starting from the folder called “base”, everything inside it will be converted into a route. “healthcheck.js” is placed directly inside the base folder, so this will become “/healthcheck”.

从名为“ base”的文件夹开始,其中的所有内容都将转换为路线。 “ healthcheck.js”直接放置在基本文件夹中,因此它将变为“ / healthcheck”。

Any files inside a folder will have the folder name as the prefix. i.e the file

文件夹中的所有文件都将以文件夹名称作为前缀。 即文件

base/todo-item/:id.delete.js 

will become

会变成

DELETE /todo-item/:id

Furthermore

此外

base/todo-item/:index.get.js

will become

会变成

GET /todo-item

最后的想法 (Final thoughts)

The biggest advantage I get by utilizing this approach is that all the information related to my route is present inside one file. This saves me time hopping between a bunch of files to find out what the request type is, the request path, middleware and etc.

利用这种方法所获得的最大好处是,与我的路线有关的所有信息都存在于一个文件中。 这节省了我在一堆文件之间跳来找出请求类型,请求路径,中间件等的时间。

Let me know what you thought about this approach.

让我知道您对这种方法的想法。

(Code)

You can find the code in my Github repo.

您可以在我的Github存储库中找到代码。

翻译自: https://medium.com/swlh/a-simplified-technique-for-express-routing-b265af1dd6a0

tp5.1路由简化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值