使用Node.js和Express构建REST API:连接数据库
在第一个教程“ 了解RESTful API”中 ,我们了解了REST体系结构是什么,HTTP请求方法和响应是什么,以及如何理解RESTful API端点。 在第二篇教程“ 如何设置Express API服务器”中 ,我们学习了如何使用Node的内置http
模块和Express框架来构建服务器,以及如何将我们创建的应用程序路由到不同的URL端点。
当前,当API端点被GET
请求命中时,我们正在使用静态数据以JSON feed的形式显示用户信息。 在本教程中,我们将设置一个MySQL数据库来存储所有数据,从Node.js应用程序连接到数据库,并允许API使用GET
, POST
, PUT
和DELETE
方法来创建一个完整的API。
安装
到目前为止,我们还没有使用数据库来存储或操作任何数据,因此我们将建立一个数据库。 本教程将使用MySQL,如果您已经在计算机上安装MySQL,则可以继续进行下一步。
如果未安装MySQL,则可以下载适用于macOS和Windows的MAMP ,它们提供了免费的本地服务器环境和数据库。 下载完成后,打开程序并单击启动服务器以启动MySQL。
除了设置MySQL本身之外,我们还希望GUI软件可以查看数据库和表。 对于Mac,下载SequelPro ,对于Windows,下载SQLyog 。 下载并运行MySQL之后,可以使用SequelPro或SQLyog使用用户名root
和密码root
在端口3306
上连接到localhost
。
在这里设置完所有内容后,我们可以继续为我们的API设置数据库。
设置数据库
在数据库查看软件中,添加一个新数据库并将其命名为api
。 确保MySQL正在运行,否则您将无法连接到localhost
。
创建api
数据库后,将其移至其中并运行以下查询以创建新表。
CREATE TABLE `users` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(30) DEFAULT '',
`email` varchar(50) DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
此SQL查询将创建我们的users
表的结构。 每个用户都有一个自动递增的ID,一个名称和一个电子邮件地址。
通过运行INSERT
查询,我们还可以使用当前通过静态JSON数组显示的数据填充数据库。
INSERT INTO users (name, email)
VALUES ('Richard Hendricks', 'richard@piedpiper.com'),
('Bertram Gilfoyle', 'gilfoyle@piedpiper.com');
由于id
字段是自动递增的,因此无需输入。 至此,我们已经有了表的结构以及一些示例数据。
连接到MySQL
回到我们的应用程序中,我们必须从Node.js连接到MySQL才能开始使用数据。 之前,我们安装了mysql
npm模块,现在我们将使用它。
创建一个名为data的新目录,并创建一个config.js文件。
我们首先需要在data / config.js中使用mysql
模块。
const mysql = require('mysql');
让我们创建一个包含主机,用户,密码和数据库的config
对象。 这应该引用我们制作的api
数据库,并使用默认的localhost设置。
// Set database connection credentials
const config = {
host: 'localhost',
user: 'root',
password: 'root',
database: 'api',
};
为了提高效率,我们将创建一个MySQL池 ,该池允许我们一次使用多个连接,而不必手动打开和关闭多个连接。
// Create a MySQL pool
const pool = mysql.createPool(config);
最后,我们将导出MySQL池,以便应用程序可以使用它。
// Export the pool
module.exports = pool;
您可以在我们的GitHub存储库中看到完整的数据库配置文件。
现在我们已经连接到MySQL并且我们的设置已经完成,我们可以继续通过API与数据库进行交互。
从MySQL获取API数据
当前,我们的routes.js
文件正在手动创建用户的JSON数组,如下所示。
const users = [{ ...
由于我们将不再使用静态数据,因此我们可以删除整个数组,并用指向我们的MySQL池的链接替换它。
// Load the MySQL pool connection
const pool = require('../data/config');
以前, /users
路径的GET
是发送静态users
数据。 我们更新的代码将改为在数据库中查询该数据。 我们将使用SQL查询从users
表中SELECT
所有内容,如下所示。
SELECT * FROM users
使用pool.query()
方法,这是我们新的/users
获取路由的样子。
// Display all users
app.get('/users', (request, response) => {
pool.query('SELECT * FROM users', (error, result) => {
if (error) throw error;
response.send(result);
});
});
在这里,我们正在运行SELECT
查询,然后通过/users
端点将结果作为JSON发送到客户端。 如果重新启动服务器并导航到/users
页面,您将看到与以前相同的数据,但是现在它是动态的。
使用URL参数
到目前为止,我们的端点是静态路径- /
root或/users
users-但是当我们只想查看有关特定用户的数据时该怎么办? 我们将需要使用变量端点。
对于我们的用户,我们可能希望根据每个用户的唯一ID检索信息。 为了做到这一点,我们将使用一个冒号( :
)表示,这是一个路由参数。
// Display a single user by ID
app.get('/users/:id', (request, response) => {
...
});
});
我们可以使用request.params
属性检索此路径的参数。 由于我们的名字叫id
,所以我们将使用它来命名它。
const id = request.params.id;
现在,我们将WHERE
子句添加到SELECT
语句中,以仅获取具有指定id
。
我们将使用?
作为占位符以避免SQL注入并通过id作为参数传递,而不是构建级联字符串,这会降低安全性。
pool.query('SELECT * FROM users WHERE id = ?', id, (error, result) => {
if (error) throw error;
response.send(result);
});
现在,我们个人用户资源的完整代码如下所示:
// Display a single user by ID
app.get('/users/:id', (request, response) => {
const id = request.params.id;
pool.query('SELECT * FROM users WHERE id = ?', id, (error, result) => {
if (error) throw error;
response.send(result);
});
});
现在,您可以重新启动服务器并导航到https://localhost/users/2
以仅查看有关Gilfoyle的信息。 如果遇到诸如Cannot GET /users/2
类的错误,则意味着您需要重新启动服务器。
转到该URL应该返回一个结果。
[{
id: 2,
name: "Bertram Gilfoyle",
email: "gilfoyle@piedpiper.com"
}]
如果您看到的是这样,那么恭喜您:您已经成功设置了动态路由参数!
发送POST请求
到目前为止,我们一直在使用GET
请求。 这些请求是安全的,这意味着它们不会更改服务器的状态。 我们只是在查看JSON数据。
现在,我们将开始通过使用POST
请求添加新数据来使API真正具有动态性。
我之前在理解REST文章中提到过,我们在URL中不使用诸如add
或delete
类的动词来执行操作。 为了向数据库中添加新用户,我们将POST
到我们从中查看用户的相同URL,但只需为其设置单独的路由。
// Add a new user
app.post('/users', (request, response) => {
...
});
请注意,我们现在使用的是app.post()
而不是app.get()
。
由于创建而不是读取,因此我们将在此处使用INSERT
查询,就像在初始化数据库时一样。 我们会将整个request.body
发送到SQL查询。
pool.query('INSERT INTO users SET ?', request.body, (error, result) => {
if (error) throw error;
我们还将指定响应的状态为201
,代表Created
。 为了获取最后插入的项目的ID,我们将使用insertId
属性。
response.status(201).send(`User added with ID: ${result.insertId}`);
我们整个POST
接收代码将如下所示。
// Add a new user
app.post('/users', (request, response) => {
pool.query('INSERT INTO users SET ?', request.body, (error, result) => {
if (error) throw error;
response.status(201).send(`User added with ID: ${result.insertId}`);
});
});
现在,我们可以通过发送POST
请求。 在大多数情况下,发送POST
请求时,都是通过Web表单进行的。 我们将在本文结尾处学习如何进行设置,但是发送测试POST
的最快,最简单的方法是使用cURL,并使用-d (--data)
标志。
我们将运行curl -d
,然后运行包含所有键/值对和请求端点的查询字符串。
curl -d "name=Dinesh Chugtai&email=dinesh@piedpiper.com" http://localhost:3002/users
通过发送此请求后,您应该从服务器获得响应。
User added with ID: 3
如果导航到http://localhost/users
,则会看到最新条目添加到列表中。
发送PUT请求
POST
对于添加新用户很有用,但是我们将要使用PUT
修改现有用户。 PUT
是幂等的,这意味着您可以多次发送同一请求,并且将仅执行一项操作。 这与POST
不同,因为如果我们多次发送新用户请求,它将继续创建新用户。
对于我们的API,我们将设置PUT
以能够编辑单个用户,因此这次我们将使用:id
route参数。
让我们创建一个UPDATE
查询,并确保它仅适用于带有WHERE
子句的请求的ID。 我们使用两个?
占位符,我们传递的值将按顺序排列。
// Update an existing user
app.put('/users/:id', (request, response) => {
const id = request.params.id;
pool.query('UPDATE users SET ? WHERE id = ?', [request.body, id], (error, result) => {
if (error) throw error;
response.send('User updated successfully.');
});
});
对于我们的测试,我们将编辑用户2
并将电子邮件地址从gilfoyle@piedpiper.com更新为bertram@piedpiper.com 。 我们可以再次使用cURL,并使用[-X (--request)]
标志,以明确指定我们正在通过发送PUT请求。
curl -X PUT -d "name=Bertram Gilfoyle" -d "email=bertram@piedpiper.com" http://localhost:3002/users/2
在发送请求之前,请确保重新启动服务器,否则您将收到Cannot PUT /users/2
错误。
您应该看到以下内容:
User updated successfully.
现在应更新ID为2
的用户数据。
发送删除请求
完成API的CRUD功能的最后一项任务是提供一个从数据库中删除用户的选项。 该请求将对WHERE
使用DELETE
SQL查询,并将删除route参数指定的单个用户。
// Delete a user
app.delete('/users/:id', (request, response) => {
const id = request.params.id;
pool.query('DELETE FROM users WHERE id = ?', id, (error, result) => {
if (error) throw error;
response.send('User deleted.');
});
});
我们可以再次使用-X
和cURL来发送删除内容。 让我们删除我们创建的最新用户。
curl -X DELETE http://localhost:3002/users/3
您会看到成功消息。
User deleted.
导航到http://localhost:3002
,您将看到现在只有两个用户。
恭喜你! 至此,API已完成。 访问GitHub存储库以查看route.js的完整代码 。
通过request
模块发送请求
在本文开始时,我们安装了四个依赖项,其中之一是request
模块。 除了使用cURL请求之外,您还可以使用所有数据制作一个新文件并通过它发送。 我将创建一个名为post.js的文件,该文件将通过POST
创建一个新用户。
const request = require('request');
const json = {
"name": "Dinesh Chugtai",
"email": "dinesh@piedpiper.com",
};
request.post({
url: 'http://localhost:3002/users',
body: json,
json: true,
}, function (error, response, body) {
console.log(body);
});
当服务器运行时,我们可以在新的终端窗口中使用node post.js
来调用它,其效果与使用cURL相同。 如果cURL无法正常工作,则request
模块非常有用,因为我们可以查看错误,响应和正文。
通过Web表单发送请求
通常,使用HTML表单发送POST
和其他更改服务器状态的HTTP方法。 在这个非常简单的示例中,我们可以在任何地方创建index.html文件,并为名称和电子邮件地址创建一个字段。 表单的操作将指向资源,在本例中为http//localhost:3002/users
,我们将方法指定为post
。
创建index.html并添加以下代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Node.js Express REST API</title>
</head>
<body>
<form action="http://localhost:3002/users" method="post">
<label for="name">Name</label>
<input type="text" name="name">
<label for="email">Email</label>
<input type="email" name="email">
<input type="submit">
</form>
</body>
</html>
在浏览器中打开此静态HTML文件,填写并在服务器在终端中运行时发送。 您应该看到User added with ID: 4
的User added with ID: 4
的响应,并且您应该能够查看新的用户列表。
结论
在本教程中,我们学习了如何将Express服务器连接到MySQL数据库,以及如何设置与路径和动态路由参数的GET
, POST
, PUT
和DELETE
方法相对应的路由。 我们还学习了如何使用cURL,Node.js request
模块和HTML表单将HTTP请求发送到API服务器。
至此,您应该对RESTful API的工作原理有了很好的了解,现在您可以使用Express和MySQL在Node.js中创建自己的完整API!