Build a REST API with Node.js, Express, and MySQL

Mr.Dabaoqiang大约 6 分钟

Build a REST API with Node.js, Express, and MySQL

在本教程中,我们将学习如何使用 MySQL 作为我们的数据库和 Node.js 作为我们的语言来构建 REST API。

我们还将使用 Express.js 框架来简化我们的任务。我们的示例 REST API 将跟踪最流行的编程语言。

先决条件

  • 了解 MySQL 和关系数据库的一般工作方式
  • Node.js和Express的基本知识.js
  • 了解什么是 REST(具象状态传输)APIopen in new window 以及它们如何工作
  • 了解什么是 CRUD(创建、读取、更新、删除)以及它与 HTTP 方法的关系、、 和GET``POST``PUT``DELETE

什么是MySQL?

MySQL是世界上最受欢迎的数据库之一,如果不是最流行的。根据 2020 年堆栈溢出调查open in new window,MySQL 是最受欢迎的数据库,超过 55% 的受访者使用它。社区open in new window是免费提供的,由一个庞大而活跃的社区提供支持。

docker 安装mysql

docker中下载 mysql

  docker pull mysql

启动

docker run -p 3306:3306 --name mysql -v /opt/docker_v/mysql/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=765365 -d [imageID]

命令说明:

-p 3306:3306:将容器的3306端口映射到主机的3306端口 -v /opt/docker_v/mysql/conf:/etc/mysql/conf.d:将主机/opt/docker_v/mysql/conf目录挂载到容器的/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=123456:初始化root用户的密码 -d: 后台运行容器,并返回容器ID imageID: mysql镜像ID

进入容器

docker exec -it mysql bash

登录mysql

mysql -u root -p
ALTER USER 'root'@'localhost' IDENTIFIED BY '786345!';

添加远程登录用户

CREATE USER 'xq'@'%' IDENTIFIED WITH mysql_native_password BY '786345!';
GRANT ALL PRIVILEGES ON *.* TO 'xq'@'%';

CRUD集成

初始化项目

mkdir programming-languages-api && cd programming-languages-api

要使用 Express.js 服务器设置 Node.js 应用程序,我们首先要为我们的项目创建一个目录:

然后,我们可以使用 npm init -y 创建一个 package.json 文件,如下所示:

npm init -y
{
  "name": "programming-languages-api",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

要安装 Express,我们将运行 npm i express,将 Express 添加为 package.json 文件中的依赖项。接下来,我们将在 index.js 文件中创建一个 slim 服务器。 它将在主路径 / 上打印一条 ok 消息:

const express = require("express");
const app = express();
const port = 3000;
//使用内置的 Express JSON 解析器中间件来解析 JSON
app.use(express.json());
app.use(
  // express.urlencoded() 中间件来解析 URL 编码主体
  express.urlencoded({
    extended: true,
  })
);
app.get("/", (req, res) => {
  res.json({ message: "ok" });
});
app.listen(port, () => {
  console.log(`Example app listening at http://localhost:${port}`);
});

REST API 项目结构

我们将按以下方式构建我们的项目,以在文件夹中逻辑安排我们的文件:

config.js

将包含信息的配置,例如数据库凭据和我们希望在对结果进行分页时每页显示的行。

helper.js

是任何辅助函数的家,比如计算分页的偏移量。

routes/programmingLanguages.js

文件将充当 URI 和 services/programmingLanguages.js 服务中相应函数之间的粘合剂。 服务文件夹将存放我们所有的服务。 其中之一是 db.js,我们用它来与 MySQL 数据库对话。

另一个服务是 programmingLanguages.js,它将具有 getMultiple、create 等方法来获取和创建编程语言资源。 URI 和相关服务功能的基本映射类似于以下代码:

GET /programming-languages → getMultiple()
POST /programming-languages → create()
PUT /programming-languages/:id → update()
DELETE /programming-languages/:id → remove()

现在,让我们编写带有分页的 GET 编程语言 API。

配置数据库连接

要创建我们的 GET 编程语言 API,我们需要将我们的 Node.js 服务器与 MySQL 链接起来。 为此,我们将使用 npm 中的 mysql2 包,我们可以在项目根目录下使用 npm i mysql2 命令安装它。

安装依赖

npm i mysql2

项目的根目录下创建配置文件

config.js

const config = {
    db: {
      /* don't expose password or any sensitive info, done only for demo */
      host: "101.43.18.117",
      user: "xq",
      password: "xq123!",
      database: "test",
    },
    listPerPage: 10,
  };
  module.exports = config;

分页配置

helper.js

function getOffset(currentPage = 1, listPerPage) {
  return (currentPage - 1) * [listPerPage];
}

function emptyOrRows(rows) {
  if (!rows) {
    return [];
  }
  return rows;
}

module.exports = {
  getOffset,
  emptyOrRows
}

持久层编写

services/db.js

我们将连接到数据库并在 services/db.js 文件中启用对数据库的运行查询语句

// 导入mysql模块
const mysql = require('mysql2/promise');
// 获取数据库配置
const config = require('../config');
// 自定义查询语句函数
async function query(sql, params) {
  const connection = await mysql.createConnection(config.db);
  const [results, ] = await connection.execute(sql, params);
  return results;
}
module.exports = {
  query
}

服务层编写

services/programmingLanguage.js

const db = require('./db');
const helper = require('../helper');
const config = require('../config');

async function getMultiple(page = 1){
  const offset = helper.getOffset(page, config.listPerPage);
  const rows = await db.query(
    `SELECT id, name, released_year, githut_rank, pypl_rank, tiobe_rank 
    FROM programming_languages LIMIT ${offset},${config.listPerPage}`
  );
  const data = helper.emptyOrRows(rows);
  const meta = {page};

  return {
    data,
    meta
  }
}

module.exports = {
  getMultiple
}

路由层编写

处理url业务

const express = require('express');
const router = express.Router();
// 路由层调用服务层,服务层调用持久层,持久层调用数据库连接层
const programmingLanguages = require('../services/programmingLanguage');

/* GET programming languages. */
router.get('/', async function(req, res, next) {
  try {
    res.json(await programmingLanguages.getMultiple(req.query.page));
  } catch (err) {
    console.error(`Error while getting programming languages `, err.message);
    next(err);
  }
});

module.exports = router;

程序入口注入路由

index.js

const express = require("express");
const app = express();
const port = 3000;
// 导入路由
const programmingLanguagesRouter = require("./routes/programmingLanguages");
// json格式
app.use(express.json());
app.use(
  express.urlencoded({
    extended: true,
  })
);
app.get("/", (req, res) => {
  res.json({ message: "ok" });
});
// 注入路由
app.use("/programming-languages", programmingLanguagesRouter);
/* Error handler middleware */
app.use((err, req, res, next) => {
  const statusCode = err.statusCode || 500;
  console.error(err.message, err.stack);
  res.status(statusCode).json({ message: err.message });
  return;
});
app.listen(port, () => {
  console.log(`Example app listening at http://localhost:${port}`);
});

查询效果

image-20230302111619078
image-20230302111619078

第三方API集成

在本节中,我们将构建一个调用 Node.js 中的 API 的小程序。稍后,我将介绍一个示例应用程序,希望它可以展示 API 调用如何适合更大的 Web 应用程序。

1.在 RapidAPI 上注册一个免费帐户

https://rapidapi.com/open in new window

2.订阅API

https://rapidapi.com/developer/dashboardopen in new window

查找星座信息并不能发挥 API 的全部功能。然而,RapidAPI 有一个有趣的娱乐类别open in new window,可以很好地用于小型应用程序。

3.设置项目

打开一个新的终端。

在终端中运行以下命令。

$ mkdir node-api-call
$ cd node-api-call
$ npm init -y

这些命令创建一个新目录,将终端移动到该目录中,并初始化一个新的 Node.js 项目。

现在我们已经初始化了一个 Node.js 项目,我们可以安装模块了。

4.安装模块

npm install --save axios

5.获取调用js

https://rapidapi.com/googlecloud/api/google-translate1open in new window

const axios = require("axios");

const encodedParams = new URLSearchParams();
encodedParams.append("q", "English is hard, but detectably so");

const options = {
  method: 'POST',
  url: 'https://google-translate1.p.rapidapi.com/language/translate/v2/detect',
  headers: {
    'content-type': 'application/x-www-form-urlencoded',
    'Accept-Encoding': 'application/gzip',
    'X-RapidAPI-Key': 'yourapikey',
    'X-RapidAPI-Host': 'google-translate1.p.rapidapi.com'
  },
  data: encodedParams
};

axios.request(options).then(function (response) {
	console.log(response.data);
}).catch(function (error) {
	console.error(error);
});

6.进行异步API调用

translateConfig.js

底层调用实现

const axios = require("axios");

const BASE_URL = `https://google-translate1.p.rapidapi.com`

const encodedParams = (q, target, source) => {
    const encodedParams = new URLSearchParams();
    encodedParams.append("q", q);
    encodedParams.append("target", "zh");
    encodedParams.append("source", "en");
    return encodedParams;
};

module.exports = {
    translateMessage: (content, source, target) => axios({
        method: "POST",
        url: BASE_URL + `/language/translate/v2`,
        headers: {
            'content-type': 'application/x-www-form-urlencoded',
            'Accept-Encoding': 'application/gzip',
            'X-RapidAPI-Key': 'yourapikey',
            'X-RapidAPI-Host': 'google-translate1.p.rapidapi.com'
        },
        data: encodedParams(content, target, source),
    })
}

translateApi.js

进行接口封装

const AstrologyAPI = require('./translateConfig')

const translateApi = async (translate) => {
    console.log(translate.contents)
    const response = await AstrologyAPI.translateMessage(translate.contents, 'en', 'zh')
    return response.data.data.translations[0];
}

module.exports = {
    translateApi
}

7.路由层新增

const thirdApi = require('../services/translateApi')
/* translate */
router.post('/translate', async function (req, res, next) {
    try {
        console.log(req.body)
        res.json(await thirdApi.translateApi(req.body));
    } catch (err) {
        console.error(`Error while translate `, err.message);
        next(err);
    }
});

8.效果

image-018
image-018

代码地址

node-back/Express-Mysql-Crud at main · dabaoqiang/node-back (github.com)open in new window

https://rapidapi.com/blog/how-to-use-an-api-with-node-js/open in new window