使用Node.js、MongoDB、Fastify 构建API服务

本文涉及的产品
云数据库 MongoDB,独享型 2核8GB
推荐场景:
构建全方位客户视图
简介: 在现代WEB开发中,数据交互是主要需求,那么对于前后端数据交互来说,REST API 就是其中的数据交互设计的一种,如何设计 REST API ? 对 API 体验至关重要,API 设计的好坏直接影响开发效率,这里就不详细展开介绍,如对 API 设计有兴趣可以参阅专栏《布道API》。

在现代WEB开发中,数据交互是主要需求,那么对于前后端数据交互来说,REST API 就是其中的数据交互设计的一种,如何设计 REST API ? 对 API 体验至关重要,API 设计的好坏直接影响开发效率,这里就不详细展开介绍,如对 API 设计有兴趣可以参阅专栏《布道API》。

本文介绍如何使用 Node.js、MongoDBFastifySwagger构建API服务。

该项目的源代码地址:github.com/QuintionTan…

开始之前

下面是需要用到的技术框架如下:

  • Fastify:用于 Node.js 的快速且低开销的 Web 框架;
  • Mongoose:优雅 mongodb 对象建模框架;
  • Swagger:使用最广泛的开源工具集之一,用于使用 OpenAPI 规范开发 API。

需要安装的环境:

  • Node.js/npm:开发运行的环境;
  • MongoDB:开源,高性能的NoSQL数据库,支持索引、集群、复制和故障转移、各种语言的驱动程序,高伸缩性;
  • Postman:是google开发的一款功能强大的网页调试与发送网页HTTP请求,常用于模拟或者测试后端API。

开始构建

打开终端创建项目目录 mkdir restful-api ,进入目录创建代码文件夹 mkdir src,再进入目录 src ,创建文件 index.js

回到项目根目录初始化项目 npm init,完成后,将会在项目目录中生成package.json文件。

接下来,将安装所需的依赖项:

npm install nodemon mongoose fastify fastify-swagger boom --save

下面对安装的相关依赖包进行简单的介绍,都是来自官方的介绍:

nodemon

是一个工具,通过在检测到目录中的文件更改来自动重新启动 Node.js 应用服务,减少手动重启的繁琐。

nodemon 不需要对代码或开发逻辑进行任何额外的更改,只需要更改项目启动方式,修改 package.json 文件,如下:

"dev": "nodemon --trace-warnings ./src/index.js",

Mongoose

Mongoose 提供了一个直接的、基于模式的解决方案来为应用程序数据建模。它包括内置的类型转换、验证、查询构建、业务逻辑挂钩等,开箱即用。

Fastify

Fastify 是一个高度专注于以最少的开销和强大的插件架构提供最佳开发者体验的 Web 框架。它的灵感来自 Hapi 和 Express,算是最快的 Web 框架之一。

fastify-swagger

Fastify 的 Swagger 文档生成器,它使用在路由中声明的模式来生成符合 swagger 的文档。

boom

boom 提供了一组用于返回 HTTP 错误的实用程序。

启动服务并创建路由

打开文件 src/index.js ,增加如下代码:

const fastify = require("fastify")({
    logger: true,
});
// 定义路由
fastify.get("/", async (request, reply) => {
    return { message: "Hello Restful Api" };
});
// 启动服务
const start = async () => {
    try {
        await fastify.listen(8100);
        fastify.log.info(`服务运行端口: ${fastify.server.address().port}`);
    } catch (err) {
        fastify.log.error(err);
        process.exit(1);
    }
};
start();

引入 Fastify 框架,声明项目的第一个路由,并定义服务运行端口 8100 ,初始化 Fastify 时启用了内置 logger,默认情况下是禁用的。

const fastify = require("fastify")({
    logger: true,
});

现在可以在终端的项目根目录中运行以下代码:

npm run dev

打开浏览器输入 http://127.0.0.1:8100/ 可以看到返回的信息如下:

{"message":"Hello Restful Api"}

接下里来设置数据库 MongoDB

启动 MongoDB 并创建模型

成功安装 MongoDB 后,可以打开一个新的终端窗口并通过运行以下命令启动 MongoDB 实例:

mongod

使用 MongoDB,不需要创建数据库。可以在设置中指定一个名称,一旦存储数据,MongoDB 就会创建这个数据库。

打开文件 src/index.js ,增加如下代码:

const mongoose = require("mongoose");
// 连接数据库
mongoose
    .connect("mongodb://localhost/crayon-restful-service")
    .then(() => console.log("MongoDB 已连接"))
    .catch((err) => console.log(err));

在上面的代码中,使用 Mongoose 创建并连接 MongoDB 数据库,该数据库名为 crayon-restful-service,如果一切顺利,将在终端中看到 MongoDB 已连接

在数据库已经启动并运行,可以创建项目的第一个数据模型。在 src 目录中创建文件夹 models ,并在其中创建文件 Coffee.js 并增加以下代码:

const { Schema, model } = require("mongoose");
const coffeeSchema = new Schema({
    title: String,
    ratio: String,
    cup: String,
    description: String,
});
module.exports = model("Coffee", coffeeSchema);

上面的代码声明了 coffeeSchema,其中包含与 Coffee 相关的基本信息,然后导出 coffeeSchema 以便后面应用程序中使用。

创建控制器

src 目录中创建文件夹 controllers ,并在该文件夹中创建文件 coffeeController.js 代码如下:

const boom = require("boom");
// 导入数据 Models
const Coffee = require("../models/Coffee");
// 获取所有的 Coffees
exports.getList = async (req, res) => {
    try {
        const coffees = await Coffee.find();
        return coffees;
    } catch (err) {
        throw boom.boomify(err);
    }
};
// 通过ID获取单个Coffee信息
exports.get = async (req, res) => {
    try {
        const id = req.params.id;
        const coffee = await Coffee.findById(id);
        return coffee;
    } catch (err) {
        throw boom.boomify(err);
    }
};
// 新增
exports.add = async (req, res) => {
    try {
        const coffee = new Coffee(req.body);
        return coffee.save();
    } catch (err) {
        throw boom.boomify(err);
    }
};
// 更新
exports.update = async (req, res) => {
    try {
        const id = req.params.id;
        const coffee = req.body;
        const { ...updateData } = coffee;
        const update = await Coffee.findByIdAndUpdate(id, updateData, {
            new: true,
        });
        return update;
    } catch (err) {
        throw boom.boomify(err);
    }
};
// 删除
exports.delete = async (req, res) => {
    try {
        const id = req.params.id;
        const coffee = await Coffee.findByIdAndRemove(id);
        return coffee;
    } catch (err) {
        throw boom.boomify(err);
    }
};

上面的代码看起来有点多,但实际上只是实现了数据库的 CURD 简单。

  • 所有的异常都交给 boom 来处理:boom.boomify(err)
  • 每个函数都是一个异步函数,可以包含一个 await 表达式,该表达式暂停异步函数的执行并等待结果传递的 Promise 来解析,并返回解析的值。
  • 每个函数都包含在 try/catch 语句中。
  • 每个函数都有两个参数:req(请求)和 res(响应)。

创建和导入路由

同样在 src 目录中创建文件夹 routes ,并在目录中创建文件 index.js ,新增以下代码:

const coffeeController = require("../controllers/coffeeController");
const APIPATH = "/api/";
const VERSION = "v1";
const ENDPOINT = "/coffees";
const getFullPath = (method = "") => `${APIPATH}${VERSION}${ENDPOINT}${method}`;
const routes = [
    {
        method: "GET",
        url: getFullPath(),
        handler: coffeeController.getList,
    },
    {
        method: "GET",
        url: getFullPath("/:id"),
        handler: coffeeController.get,
    },
    {
        method: "POST",
        url: getFullPath(),
        handler: coffeeController.add,
    },
    {
        method: "PUT",
        url: getFullPath("/:id"),
        handler: coffeeController.update,
    },
    {
        method: "DELETE",
        url: getFullPath("/:id"),
        handler: coffeeController.delete,
    },
];
module.exports = routes;

上面的代码定义了接口路由,并设置其控制器方法。每个路由都由一个方法、一个 URL 和一个 handler 处理程序组成,配置应用程序在访问其中一个路由时使用哪个控制器方法。

一些路由后面的 :id 是表示向路由传递参数的常用方式,可以按照下面的方式传递参数 id

http://127.0.0.1:8100/api/v1/coffees/6235a1b03797442599fb6fc7

创建 API 文档

一个好的 API 服务需要齐全的说明文档,过去都是手动排版编写,现在这些事情都可以借助工具。本文将使用 Swagger 来对文档进行支持。

src 目录中创建文件夹 config ,并在目录中创建文件 swagger.js ,新增以下代码:

exports.options = {
    routePrefix: "/api/v1/helper",
    exposeRoute: true,
    swagger: {
        info: {
            title: "Coffee Restful API",
            description:
                "使用Node.js、MongoDB、Fastify 和 Swagger 构建基于 RESTFUL 风格的咖啡 API",
            version: "1.0.0",
        },
        stripBasePath: true,
        host: "localhost",
        basePath: "/api/v1",
        externalDocs: {
            url: "https://swagger.io",
            description: "更多信息",
        },
        schemes: ["http"],
        consumes: ["application/json"],
        produces: ["application/json"],
    },
};

上面的代码是 Swagger 的简单配置,将其传递给 fastify-swagger 插件,需要将以下添加到  src/index.js 文件中:

const swagger = require("./config/swagger");

然后将以下代码添加到 fastify 定义之后,如下:

const fastify = require("fastify")({
    logger: true,
});
fastify.register(require("fastify-swagger"), swagger.options);

然后,需要在初始化 Fastify 服务器后添加一下代码:

await fastify.listen(8100);
fastify.swagger();

现在在浏览器中打开 http://localhost:8100/api/v1/helper,可以看到以下内容:

image.png

从上图可以看出,接口没有任何的说明,接下来需要增加详细的接口说明信息。

src 目录中创建文件夹 docs ,并在目录中创建文件 coffess.js ,新增以下代码:

const coffeeBody = {
    type: "object",
    properties: {
        _id: { type: "string" },
        title: { type: "string", description: "种类名称" },
        ratio: { type: "string" },
        cup: { type: "string" },
        description: { type: "string" },
        __v: { type: "number" },
    },
};
exports.coffeesSchema = {
    list: {
        description: "获取咖啡种类列表",
        tags: ["coffees"],
        summary: "获取所有的咖啡种类列表",
        response: {
            200: {
                description: "获取成功",
                type: "array",
            },
        },
    },
    detail: {
        description: "获取咖啡种类详情",
        tags: ["coffees"],
        summary: "通过id获取咖啡种类详情",
        querystring: {
            type: "object",
            properties: {
                id: {
                    type: "string",
                },
            },
        },
        response: {
            200: {
                description: "获取成功",
                ...coffeeBody,
            },
        },
    },
    add: {
        description: "创建新的咖啡种类",
        tags: ["coffees"],
        summary: "增加新的咖啡种类",
        body: {
            ...coffeeBody,
        },
        response: {
            200: {
                description: "创建成功",
                ...coffeeBody,
            },
        },
    },
    update: {
        description: "更新咖啡种类详情",
        tags: ["coffees"],
        summary: "通过id 更新咖啡种类详情",
        querystring: {
            type: "object",
            properties: {
                id: {
                    type: "string",
                },
            },
        },
        body: {
            ...coffeeBody,
        },
        response: {
            200: {
                description: "更新成功",
                ...coffeeBody,
            },
        },
    },
    delete: {
        description: "删除咖啡种类详情",
        tags: ["coffees"],
        summary: "通过id删除咖啡种类详情",
        querystring: {
            type: "object",
            properties: {
                id: {
                    type: "string",
                },
            },
        },
        response: {
            200: {
                description: "删除成功",
                type: "string",
            },
        },
    },
};

修改文件 routes/index.js,导入上面定义的API文档,如下:

const { coffeesSchema } = require("../docs/coffees");

然后再修改每个路由,增加属性 schema,再次打开文档页面,效果如下:

image.png

测试 API

至此已经构建了大部分模块,只需要将它们连接在一起,即可开始通过 API 提供进行数据交互。

首先,需要将以下代码添加到 src/index.js 文件中来导入路由信息:

const routes = require("./routes");

然后需要用 Fastify 遍历 routes 数组来进行初始化,将以下代码添加到 src/index.js 文件中:

routes.forEach((route, index) => {
    fastify.route(route);
});

到此一个简单的 REST API 服务已经完成, 可以准备开始测试了!

测试 API 最佳的工具就是 Postman,它可以模拟 API 的数据进行测试。

新增数据

image.png

获取列表

image.png

获取详情

image.png

部署

关于Node.js构建的服务,在部署中可以通过 pm2 来启动,或者通过 docker 来部署,这里就不展开介绍了,推荐两个相关内容:

总结

到这里一个完整的 REST API 构建完成,只是一个简单的示例,可以作为 Node.js 后端服务的基础,在此基础上迭代更加丰富的服务。目前实例没有加入model 字段的验证规则、列表的分页等复杂逻辑,后续可以持续迭代,文章中创建目录的过程可以通过构建脚手架插件在项目初始化的过程中自动完成目录及文件的创建。在下一篇文章《在 Node.js 中使用 Yaml 编写API文档》介绍使用 Yaml 编写API文档,将文档与接口实现分离。


相关实践学习
MongoDB数据库入门
MongoDB数据库入门实验。
快速掌握 MongoDB 数据库
本课程主要讲解MongoDB数据库的基本知识,包括MongoDB数据库的安装、配置、服务的启动、数据的CRUD操作函数使用、MongoDB索引的使用(唯一索引、地理索引、过期索引、全文索引等)、MapReduce操作实现、用户管理、Java对MongoDB的操作支持(基于2.x驱动与3.x驱动的完全讲解)。 通过学习此课程,读者将具备MongoDB数据库的开发能力,并且能够使用MongoDB进行项目开发。   相关的阿里云产品:云数据库 MongoDB版 云数据库MongoDB版支持ReplicaSet和Sharding两种部署架构,具备安全审计,时间点备份等多项企业能力。在互联网、物联网、游戏、金融等领域被广泛采用。 云数据库MongoDB版(ApsaraDB for MongoDB)完全兼容MongoDB协议,基于飞天分布式系统和高可靠存储引擎,提供多节点高可用架构、弹性扩容、容灾、备份回滚、性能优化等解决方案。 产品详情: https://www.aliyun.com/product/mongodb
相关文章
|
25天前
|
JSON 缓存 JavaScript
深入浅出:使用Node.js构建RESTful API
在这个数字时代,API已成为软件开发的基石之一。本文旨在引导初学者通过Node.js和Express框架快速搭建一个功能完备的RESTful API。我们将从零开始,逐步深入,不仅涉及代码编写,还包括设计原则、最佳实践及调试技巧。无论你是初探后端开发,还是希望扩展你的技术栈,这篇文章都将是你的理想指南。
|
18天前
|
JSON JavaScript 前端开发
深入浅出Node.js:从零开始构建RESTful API
在数字化时代的浪潮中,后端开发作为连接用户与数据的桥梁,扮演着至关重要的角色。本文将引导您步入Node.js的奇妙世界,通过实践操作,掌握如何使用这一强大的JavaScript运行时环境构建高效、可扩展的RESTful API。我们将一同探索Express框架的使用,学习如何设计API端点,处理数据请求,并实现身份验证机制,最终部署我们的成果到云服务器上。无论您是初学者还是有一定基础的开发者,这篇文章都将为您打开一扇通往后端开发深层知识的大门。
34 12
|
24天前
|
JavaScript NoSQL API
深入浅出Node.js:从零开始构建RESTful API
在数字化时代的浪潮中,后端开发如同一座灯塔,指引着数据的海洋。本文将带你航行在Node.js的海域,探索如何从一张白纸到完成一个功能完备的RESTful API。我们将一起学习如何搭建开发环境、设计API结构、处理数据请求与响应,以及实现数据库交互。准备好了吗?启航吧!
|
27天前
|
JSON 关系型数据库 测试技术
使用Python和Flask构建RESTful API服务
使用Python和Flask构建RESTful API服务
|
1月前
|
JSON JavaScript API
深入浅出Node.js:从零开始构建RESTful API
【10月更文挑战第39天】 在数字化时代的浪潮中,API(应用程序编程接口)已成为连接不同软件应用的桥梁。本文将带领读者从零基础出发,逐步深入Node.js的世界,最终实现一个功能完备的RESTful API。通过实践,我们将探索如何利用Node.js的异步特性和强大的生态系统来构建高效、可扩展的服务。准备好迎接代码和概念的碰撞,一起解锁后端开发的新篇章。
|
1月前
|
JavaScript 中间件 API
Node.js进阶:Koa框架下的RESTful API设计与实现
【10月更文挑战第28天】本文介绍了如何在Koa框架下设计与实现RESTful API。首先概述了Koa框架的特点,接着讲解了RESTful API的设计原则,包括无状态和统一接口。最后,通过一个简单的博客系统示例,详细展示了如何使用Koa和koa-router实现常见的CRUD操作,包括获取、创建、更新和删除文章。
47 4
|
28天前
|
JSON JavaScript 前端开发
使用JavaScript和Node.js构建简单的RESTful API
使用JavaScript和Node.js构建简单的RESTful API
|
2月前
|
存储 人工智能 NoSQL
使用 MongoDB 构建 AI:Gradient Accelerator Block 如何在几秒钟内让您从零开发 AI
借助 MongoDB,开发者可以存储任何结构的数据,然后使用单一查询 API 和驱动程序将这些数据用于 OLTP、文本搜索和向量搜索处理。
|
2月前
|
存储 NoSQL MongoDB
基于阿里云数据库MongoDB版,微财数科“又快又稳”服务超7000万客户
选择MongoDB主要基于其灵活的数据模型、高性能、高可用性、可扩展性、安全性和强大的分析能力。
|
1月前
|
JavaScript 前端开发 NoSQL
深入浅出:使用Node.js构建RESTful API
【10月更文挑战第35天】在数字时代的浪潮中,后端技术如同海洋中稳固的灯塔,为前端应用提供数据和逻辑支撑。本文旨在通过浅显易懂的方式,带领读者了解如何利用Node.js这一强大的后端平台,搭建一个高效、可靠的RESTful API。我们将从基础概念入手,逐步深入到代码实践,最终实现一个简单的API示例。这不仅是对技术的探索,也是对知识传递方式的一次创新尝试。让我们一起启航,探索Node.js的奥秘,解锁后端开发的无限可能。
下一篇
DataWorks