使用Express设置Rest API

文心思
2023-12-01

In this article, I want to show you a quick and solid way to set up a REST-API with ExpressJS. This does not include any kind of authentication or authorization. We will just be setting up one single route and define some standards that will help us expand this API if we chose to do so.

在本文中,我想向您展示使用ExpressJS设置REST-API的快速而可靠的方法。 这不包括任何类型的身份验证或授权。 我们将只建立一条单一的路线,并定义一些标准(如果选择这样做的话),这些标准将有助于我们扩展此API。

先决条件 (Prerequisites)

Before we can start coding we need to get a version of NodeJS and NPM installed on our system. Just head over to the official website linked here and download the LTS (long time support) version of NodeJS. This will automatically install NPM alongside it as its package manager.

在开始编码之前,我们需要在系统上安装NodeJS和NPM的版本。 只需访问此处链接的官方网站并下载NodeJS的LTS(长期支持)版本即可。 这将自动将NPM与其包管理器一起安装。

Next, we generate our project by creating a folder called express_api_template and then using npm to initialize a NodeJS project.

接下来,我们通过创建一个名为express_api_template的文件夹,然后使用npm初始化NodeJS项目来生成我们的项目。

$ mkdir express_api_template
$ cd express_api_template/
$ npm init

npm, init will walk you through a process for setting up a new project. I usually use the default settings except for entry point. I like to call my main javascript file server.js instead of the default index.js and then fill out the author. After this is done we need to install ExpressJS by adding it to our package.json. We will use the following command for this.

npm,init引导您完成设置新项目的过程。 我通常使用除入口点以外的默认设置。 我喜欢调用我的主要javascript文件server.js而不是默认的index.js ,然后填写作者。 完成此操作后,我们需要通过将ExpressJS添加到package.json中来安装它。 为此,我们将使用以下命令。

$ npm install express

After it is finished downloading we should have a node_modules folder and the two files package.json and package-lock.json.

下载完成后,我们应该有一个node_modules文件夹以及两个文件package.jsonpackage-lock.json

基础 (The Basics)

First, we need to create two new folders and two new files, and some new dependencies.

首先,我们需要创建两个新文件夹和两个新文件,以及一些新的依赖项。

$ mkdir src
$ mkdir src/config
$ touch src/server.js src/config/config.env
$ npm install colors dotenv
$ npm install nodemon --save-dev

The difference between the plain install and the — save-dev install is that the plain one installs dependencies needed for production. — save-dev installs dependencies only needed for development. But what did we actually install here?

普通安装和— save-dev安装之间的区别在于,普通安装将安装生产所需的依赖项。 — save-dev安装仅开发所需的依赖项。 但是,我们实际上在这里安装了什么?

  • colors: This package is used to make the console outputs colorful.

    colors 此软件包用于使控制台输出色彩鲜艳。

  • dotenv: This package loads environment variables from .env files into process.env.{variable_name}

    dotenv 此软件包将.env文件中的环境变量加载到process.env中。{variable_name}

  • nodemon: This is used in development for reloading your server every time you save changes.

    nodemon 在开发中用于每次保存更改时重新加载服务器。

Installing all this won’t make the application run. For that we need to do two more things:

安装所有这些将无法使应用程序运行。 为此,我们需要做两件事:

  1. Configuring our package.json to start server.js

    配置我们的package.json以启动server.js

  2. Implementing a basic Express server in server.js

    server.js中实现基本的Express服务器

Let’s start by configuring package.json like this:

让我们从这样配置package.json开始:

{
  "name": "express_api_template",
  "version": "1.0.0",
  "description": "",
  "main": "src/server.js",
  "scripts": {
    "start": "NODE_ENV=production node src/server.js",
    "dev": "NODE_ENV=development nodemon src/server.js"
  },
  "author": "Jakob Klamser",
  "license": "ISC",
  "dependencies": {
    "colors": "^1.4.0",
    "dotenv": "^8.2.0",
    "express": "^4.17.1"
  },
  "devDependencies": {
    "nodemon": "^2.0.4"
  }
}

We defined two commands to use with npm. The first one is for production. It sets the NODE_ENV variable to production and then starts the server by using the node-command. The second one is for development and is setting the NODE_ENV to development and then using nodemon instead of node so that we can make use of the reload-on-save functionality while we are in development.

我们定义了两个与npm一起使用的命令。 第一个用于生产。 它将NODE_ENV变量设置为production ,然后使用node-command启动服务器。 第二个用于开发,将NODE_ENV设置为开发,然后使用nodemon代替node,这样我们在开发时就可以使用保存时重载功能。

NOTE: If you are using Windows as an operating system you need to install cross-env as a development dependency to set the NODE_ENV.

注意:如果使用Windows作为操作系统,则需要安装cross-env作为开发依赖项以设置NODE_ENV。

$ npm install cross-env --save-dev

And then edit the two scripts like this:

然后像这样编辑两个脚本:

"scripts": {
"start": "cross-env NODE_ENV=production node src/server.js",
"dev": "cross-env NODE_ENV=development nodemon src/server.js"
},

For all of this to work, we need to finish up step two first. We have to create an express application and then start it by using a port that we define in our config.env. Add the port to the file like this:

对于所有这些工作,我们需要首先完成第二步。 我们必须创建一个快速应用程序,然后使用在config.env中定义的端口启动它。 将端口添加到文件中,如下所示:

PORT=5000

Now we can go ahead and begin with writing some code on server.js.

现在,我们可以开始在server.js上编写一些代码。

const express = require('express');
const dotenv = require('dotenv');
const colors = require('colors');


dotenv.config({ path: 'src/config/config.env' });


const app = express();


const PORT = process.env.PORT || 5001;


app.listen(PORT,
  console.log(`Server up and running in ${process.env.NODE_ENV} mode on port ${PORT}`.yellow.bold));

This is really straight forward, we set the path to our config.env and then initialize the express app. After that, we start listening at the port we just set in our config.env. If we run the following command:

这很简单,我们将路径设置为config.env ,然后初始化express应用。 之后,我们开始在刚在config.env中设置的端口上监听。 如果我们运行以下命令:

$ npm run dev

You should see the following output:

您应该看到以下输出:

[nodemon] 2.0.4
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node src/server.js`
Server up and running in development mode on port 5000

Now we got a really basic setup going. Now let’s make this a template for a REST-API in the next section.

现在我们有了一个非常基本的设置。 现在,在下一节中,使它成为REST-API的模板。

调试与安全 (Debug and Security)

Our goal is to add some more features like logging more information to the console for debugging purposes and securing the API.

我们的目标是添加更多功能,例如将更多信息记录到控制台以进行调试并保护API。

To achieve the aforementioned goals we need to add a few more dependencies.

为了实现上述目标,我们需要添加更多的依赖项。

$ npm install helmet cors
$ npm install morgan --save-dev

What do these three new dependencies do?

这三个新的依赖项有什么作用?

  • helmet: This package is a middleware that helps to secure your API by adding multiple HTTP headers.

    helmet 这个软件包是一种中间件,可通过添加多个HTTP标头来帮助保护您的API。

  • cors: This middleware helps us implementing CORS.

    cors 此中间件可帮助我们实施CORS

  • morgan: This is a simple HTTP request logger, it outputs the incoming requests to the node console.

    morgan 这是一个简单的HTTP请求记录器,它将传入的请求输出到节点控制台。

After installing all these middlewares we need to go ahead and add them to our express application.

安装所有这些中间件之后,我们需要继续并将它们添加到我们的快速应用程序中。

const express = require('express');
const dotenv = require('dotenv');
const colors = require('colors');
const helmet = require('helmet');
const cors = require('cors');


dotenv.config({ path: 'src/config/config.env' });


const app = express();


// Development Setup
if (process.env.NODE_ENV === 'development') {
  // require morgan if in development mode
  // setting morgan to dev: https://www.npmjs.com/package/morgan#dev
  app.use(require('morgan')('dev'));
}


// Put all the server-wide middleware here
app.use(cors({
  origin: process.env.CORS_ORIGIN,
}));
app.use(helmet());


const PORT = process.env.PORT || 5001;


app.listen(PORT,
  console.log(`Server up and running in ${process.env.NODE_ENV} mode on port ${PORT}`.yellow.bold));

Most notably is the new check on the current NODE_ENV. We do that because we only require morgan if we are in development mode. If you later want to add in something like a data seeding script for a database in development then you can do it right there.

最值得注意的是对当前NODE_ENV的新检查。 之所以这样做,是因为只有在处于开发模式时才需要morgan 。 如果以后要为正在开发中的数据库添加诸如数据种子脚本之类的内容,则可以在那里进行操作。

After that new check, we connect the middlewares to our express application. For cors, we configure an origin. This means only requests from this origin are allowed to communicate with our API. For example a frontend application you built. We just need to add the address to our config.env file like this:

进行新检查之后,我们将中间件连接到我们的快速应用程序。 对于cors ,我们配置一个原点。 这意味着仅允许来自此来源的请求与我们的API通信。 例如,您构建的前端应用程序。 我们只需要将地址添加到我们的config.env文件中,如下所示:

CORS_ORIGIN=http://localhost:8000

The port might be different depending on your web applications development set up. If that’s the case just go ahead and change it.

端口可能会有所不同,具体取决于您的Web应用程序开发设置。 如果是这种情况,请继续进行更改。

端点和自定义中间件 (Endpoint and Custom Middleware)

Now that we are done securing the API we will implement two basic middlewares and one example route. To keep the project clean and maintainable we will add three more folders and four new files.

既然我们已经完成了API的安全保护,我们将实现两种基本的中间件和一种示例路由。 为了保持项目的清洁性和可维护性,我们将再添加三个文件夹和四个新文件。

$ mkdir src/routes src/middleware src/controllers
$ touch src/middleware/notFound.js src/middleware/errorHandler.js src/routes/post.js src/controllers/postsController.js

中间件 (Middleware)

We start by creating our first middleware function in notFound.js that handles requests that don’t hit an API endpoint by throwing a 404 Not Found Error.

我们首先在notFound.js中创建第一个中间件函数,该函数通过抛出404 Not Found Error处理未到达API端点的请求。

const notFound = (req, res, next) => {
  const error = new Error(`Not Found - ${req.originalUrl}`);
  res.status(404);
  next(error);
};


module.exports = notFound;

It is simply a function that takes in the request, response, and next. We create an error and set the HTTP status code to 404 and pass in the error to next.

它只是一个接受请求,响应和下一步的函数。 我们创建一个错误,并将HTTP状态代码设置为404,然后将错误传递给next。

This middleware alone won’t help us at all. We need something to handle incoming errors, such as the Not Found Error we just created. For that, we implement our next middleware function called errorHandler.

仅此中间件根本无法帮助我们。 我们需要一些处理传入错误的方法,例如我们刚刚创建的Not Found Error 。 为此,我们实现了下一个称为errorHandler的中间件函数。

const errorHandler = (error, req, res, next) => {
  const statusCode = res.statusCode === 200 ? 500 : res.statusCode;
  res.status(statusCode);
  res.json({
    message: error.message,
    stack: process.env.NODE_ENV === 'production' ? ':(' : error.stack,
  });
};


module.exports = errorHandler;

If someone hits a route that has no endpoint our API will return a JSON object that contains the error message and if we are running in development it also returns the stack.

如果有人碰到没有端点的路由,我们的API将返回一个包含错误消息的JSON对象,如果我们正在开发中,它也会返回堆栈。

The last step is to add the middlewares to our server.js.

最后一步是将中间件添加到我们的server.js中

// After the other require statements:
const notFound = require('./middleware/notFound');
const errorHandler = require('./middleware/errorHandler');
// Custom middleware here
app.use(notFound);
app.use(errorHandler);

路由器 (Router)

We are getting closer to the finish line. There are just two steps left. We are focusing on one of them now: Adding a route. For that, we need to ask ourselves what route we want to add. In this article, I want to add two different GET routes one that gets all posts and one that gets an article by its ID. Let’s get started by implementing our route in the file post.js.

我们越来越接近终点线。 仅剩两个步骤。 现在,我们专注于其中之一:添加路线。 为此,我们需要问自己要添加的路线。 在本文中,我想添加两种不同的GET路由,一种获取所有帖子,另一种通过其ID获取文章。 让我们从在post.js文件中实现路由开始。

const express = require('express');


const router = express.Router();


// Controller Methods
const { getPosts, getPostById } = require('../controllers/postsController');


router.route('/')
  .get(getPosts);


router.route('/:id')
  .get(getPostById);


module.exports = router;

The express router lets us define routes based on HTTP verbs like GET, POST, etc. We just need to add our controller methods, that we will implement later, to the HTTP verb, and the router will do his magic. In server.js we need to add the router like this:

express路由器允许我们基于HTTP动词(例如GET,POST等)定义路由。我们只需要将稍后将实现的控制器方法添加到HTTP动词即可,路由器将发挥他的魔力。 在server.js中,我们需要像这样添加路由器:

// Between helmet and custom middleware:
// All routes here
app.use('/api/posts', require('./routes/post'));

This will throw an error because we did not implement the controller functions yet.

这将引发错误,因为我们尚未实现控制器功能

控制器 (Controllers)

Now we are at the last step for our REST-API template. The controller functions. We will need to create two of them, getPosts and getPostById. Let’s get to work by implementing these methods in postsController.js.

现在,我们进入了REST-API模板的最后一步。 控制器功能。 我们将需要创建其中两个,即getPostsgetPostById 。 让我们通过在postsController.js中实现这些方法开始工作

const postsArray = [
  {
    id: 1,
    title: 'React from scratch',
    content: 'In this article we will create a ToDo App in React from scratch.... etc.etc.etc.',
    author: 'Jakob Klamser'
  },
  {
    id: 2,
    title: 'Vanilla JavaScript Basics',
    content: 'Today we will discuss some basic JavaScript fundamentals like array manipulation, currying etc.',
    author: 'Jakob Klamser'
  },
  {
    id: 3,
    title: 'VS Code Extensions',
    content: 'I wanted to show you some of my favorite VS Code Extensions.... Bracket Pair Colorizer etc.etc.',
    author: 'Jakob Klamser'
  },
  {
    id: 4,
    title: 'ExpressJS REST API',
    content: 'Is this the current article?',
    author: 'Jakob Klamser'
  },
];




// @route   GET api/posts
// @desc    Get All Posts
// @access  Public
exports.getPosts = (req, res) => {
  const posts = postsArray;
  return res.status(200).json({
    success: true,
    count: posts.length,
    data: posts,
  });
};


// @route   GET api/posts/:id
// @desc    Gets a post by ID
// @access  Private
exports.getPostById = (req, res) => {
  const post = postsArray.filter(post => post.id === Number(req.params.id));
  console.log(post);
  if (post[0] !== undefined) {
    return res.status(200).json({
      success: true,
      data: post[0],
    });
  }
  return res.status(404).json({
    success: false,
    error: 'No post found',
  })
};

At the top of the file, we have some static data. After that, we export two functions. The first one, getPosts, returns the whole list of static data. The second method, getPostById, returns one object from the array if the id matches or it returns an error if no post matches the id provided in the request.

在文件的顶部,我们有一些静态数据。 之后,我们导出两个函数。 第一个,getPosts,返回静态数据的整个列表。 第二种方法getPostById,如果ID匹配,则从数组返回一个对象;如果没有帖子与请求中提供的ID匹配,则返回错误。

The last thing we need to do is enable JSON for our application by adding another middleware.

我们需要做的最后一件事是通过添加另一个中间件为我们的应用程序启用JSON。

// Right below helmet:
app.use(express.json());

After adding this our server.js should look like this:

添加后,我们的server.js应该如下所示:

const express = require('express');
const dotenv = require('dotenv');
const colors = require('colors');
const helmet = require('helmet');
const cors = require('cors');
const notFound = require('./middleware/notFound');
const errorHandler = require('./middleware/errorHandler');


dotenv.config({ path: 'src/config/config.env' });


const app = express();


// Development Setup
if (process.env.NODE_ENV === 'development') {
  // require morgan if in development mode
  // setting morgan to dev: https://www.npmjs.com/package/morgan#dev
  app.use(require('morgan')('dev'));
}


// Put all the server-wide middleware here
app.use(cors({
  origin: process.env.CORS_ORIGIN,
}));
app.use(helmet());
app.use(express.json());


// All routes here
app.use('/api/posts', require('./routes/post'));


// Custom middleware here
app.use(notFound);
app.use(errorHandler);


const PORT = process.env.PORT || 5001;


app.listen(PORT,
  console.log(`Server up and running in ${process.env.NODE_ENV} mode on port ${PORT}`.yellow.bold));

结论(Conclusion)

You can now type in http://localhost:5000/api/posts or http://localhost:5000/api/posts/2 to access the API (while it is running). I hope you enjoyed this quick guide for setting up a template express API. You can build on that by adding a database, authentication and authorization, more endpoints, and so on. Let me know what you think about it and if you build something on top of this template. The whole project can be found on my GitHub.

现在,您可以输入http:// localhost:5000 / api / postshttp:// localhost:5000 / api / posts / 2来访问API(运行时)。 希望您喜欢此快速指南,该指南用于设置模板Express API。 您可以通过添加数据库,身份验证和授权,更多端点等来建立此基础。 让我知道您对此有何想法,以及是否在此模板上构建了内容。 整个项目可以在我的GitHub上找到

翻译自: https://medium.com/javascript-in-plain-english/setting-up-a-rest-api-using-express-d92d5dc42e2a

 类似资料: