使用Swagger记录Node.js的REST API
Swagger是一个用于设计、构建、记录和使用RESTful APIs的软件工具。它遵循OpenAPI规范。
API(应用编程接口)是一个中介,它使两个不同的软件应用程序能够相互沟通。
OpenAPI规范是一个用于创建描述、生产、消费和可视化RESTful APIs的接口的规范。它也被称为swagger规范。
目标
在这篇文章中,我们将使用swagger记录一个简单的Node.js REST(Representational State Transfer)API。
前提条件
要跟上本文的进度,必须具备以下条件。
- 在你的电脑上安装[Node.js]。
- 一些JavaScript的基本知识。
- 熟悉使用[Express.js]构建REST APIs。
简介
Swagger在开发API的文档时依赖于规范。这些规范可以是YAML 或JSON 格式。
YAML(YAML Ain't Markup Language)是一种用于编写配置文件的数据序列化标准。
JSON(JavaScript Object Notation)是一种轻量级的数据序列化标准,遵循JavaScript对象语法。数据被安排在键/值对中。
在这篇文章中,我们将使用JSON 格式实现规范。通过这种格式,我们将从.js 文件。
设置开发服务器
由于主要重点是记录REST API,我们不会处理创建一个,但我们将从这个GitHub仓库克隆一个。
该API将使用以下依赖项。
- [lowdb]:用于存储数据。
- [morgan]:用于记录请求。
- [nanoid]:用于生成ID。
- [cors]:用于设置跨源策略。
- [swagger-ui-express]:用于在我们的API中提供swagger用户界面。
- [nodemon]:用于在有任何变化的情况下重新启动开发服务器。
为了安装这些依赖项,我们需要在项目的根目录下运行以下命令。
npm install
安装完依赖项后,你可以通过运行以下命令来启动开发服务器。
npm run dev
现在,开发服务器已经设置好了,我们的重点是记录API。我鼓励你浏览一下API,了解各种端点以及数据是如何交换的。
在这一点上,你可以使用[postman]。
从这里开始,我们将集中讨论src 文件夹中的docs 。
记录API的一般信息
API的一般信息包括openAPI版本openapi ,以及info 对象下的API的具体信息。
info 对象包括title,description,version,contact 等信息。
这些信息对于公开的API来说是非常值得推荐的,以提高开发者的体验。
在我们的API中,我们将记录docs/basicInfo.js 文件中的一般信息。
我们将包括但不限于以下信息。
module.exports = {
openapi: "3.0.3", // present supported openapi version
info: {
title: "Simple Todos API", // short title.
description: "A simple todos API", // desc.
version: "1.0.0", // version number
contact: {
name: "John doe", // your name
email: "john@web.com", // your email
url: "web.com", // your website
},
},
};
在写这篇文章的时候,openapi 的最新支持版本是3.0.3 。请确保将其修改为最新支持的版本。
由于我们的API很简单,所以info 对象下的信息不多。如果你有一个复杂的API,请随意添加更多的信息。
为了测试上述内容。
- 确保开发服务器从你的终端启动并运行。
- 在你的浏览器中,从
http://localhost:4000/api-docs,打开你的文档页面。 - 如果出现错误,请重新审视这些步骤。
否则,你的网页应该像下面这样。

一个关于API的一般信息的屏幕截图
记录API服务器
根据当前API的环境,它将在不同的服务器上运行。
当处于开发环境时,API在本地服务器上运行。当处于测试环境时,它在测试服务器上,而当处于生产环境时,它在生产服务器上。
在编写文档时,你要根据环境指定API所运行的不同服务器。
在我们的API中,我们将通过编辑docs/servers.js ,在开发环境中记录它,如下所示。
module.exports = {
servers: [
{
url: "http://localhost:4000/todos", // url
description: "Local server", // name
},
],
};
由于我们只在开发环境下操作这个API,我们只指定了本地服务器。如果,你要推送到测试和生产环境,请确保你包括这些信息。它遵循相同的格式。
为了测试这个。
- 确保你的开发服务器已经启动并运行。
- 在你的浏览器中,刷新文档页面。
- 如果有任何错误,请重新审视这些步骤。
否则,以下部分应该被添加到你的页面中。

API服务器的屏幕截图
记录API标签
标签用于对不同的相关操作进行分组。例如,在一个处理用户和商店的API中,你可以使用标签来区分它们各自的操作。
在我们的API中,由于我们只处理todos ,我们将只在docs/tags.js 文件中添加一个标签,如下。
module.exports = {
tags: [
{
name: "Todo CRUD operations", // name of a tag
},
],
};
在一个更复杂的API中,你有不同的当事人,你可以像上面那样在标签数组中添加每个当事人。
为了测试这一点。
- 确保开发服务器正在运行。
- 在你的浏览器中,刷新文档页面。
- 如果出现错误,重温一下步骤。
否则,这部分应该被添加到你的页面中。

API标签的屏幕截图
记录API组件
组件是用于容器化不同的可重用定义的。可重用的定义涉及到模式、参数、安全模式、requestBodies、响应、标头、示例、链接和回调。在它们的定义之后,组件可以使用$ref 。
在我们的API中,我们通过编辑docs/components.js 文件来记录组件,如下所示。
module.exports = {
components: {
schemas: {
// id model
id: {
type: "string", // data type
description: "An id of a todo", // desc
example: "tyVgf", // example of an id
},
// todo model
Todo: {
type: "object", // data type
properties: {
id: {
type: "string", // data-type
description: "Todo identification number", // desc
example: "ytyVgh", // example of an id
},
title: {
type: "string", // data-type
description: "Todo's title", // desc
example: "Coding in JavaScript", // example of a title
},
completed: {
type: "boolean", // data type
description: "The status of the todo", // desc
example: false, // example of a completed value
},
},
},
// Todo input model
TodoInput: {
type: "object", // data type
properties: {
title: {
type: "string", // data type
description: "Todo's title", // desc
example: "Coding in JavaScript", // example of a title
},
completed: {
type: "boolean", // data type
description: "The status of the todo", // desc
example: false, // example of a completed value
},
},
},
// error model
Error: {
type: "object", //data type
properties: {
message: {
type: "string", // data type
description: "Error message", // desc
example: "Not found", // example of an error message
},
internal_code: {
type: "string", // data type
description: "Error internal code", // desc
example: "Invalid parameters", // example of an error internal code
},
},
},
},
},
};
由于我们的API没有那么复杂,我们只在组件中加入了schemas 。
在schemas ,我们定义了id 、Todo 、TodoInput 、和Error 。对于每个模式的定义,我们都使用键来描述其各自的数据,如type,description,example, 和properties 。
为了测试这一点。
- 确保开发服务器正在运行。
- 在你的浏览器中,刷新文档页面。
- 如果出现错误,重温一下步骤。
以下部分应该被添加到文档页面中。

API组件的屏幕截图
记录API的路径
路径是指要访问的路线。根据操作方法和传递的数据,每条路径都是不同的。
为了记录我们API中的路径,我们将分别介绍每条路径。
获取todos (/todos)
当获取todos ,我们正在发送一个GET 请求到/todos 。
为了记录这个路径,我们编辑/docs/todos/get-todos.js 文件,如下所示。
module.exports = {
// method of operation
get: {
tags: ["Todo CRUD operations"], // operation's tag.
description: "Get todos", // operation's desc.
operationId: "getTodos", // unique operation id.
parameters: [], // expected params.
// expected responses
responses: {
// response code
200: {
description: "Todos were obtained", // response desc.
content: {
// content-type
"application/json": {
schema: {
$ref: "#/components/schemas/Todo", // Todo model
},
},
},
},
},
},
};
从上面的代码片断中,我们已经。
- 指定了操作的方法,
get。 - 指定了操作的标签。
- 用一个简短的
description和一个operationId来描述这个操作。 - 定义了
parameters。在这种情况下,没有定义。 - 定义了预期的
responses。因为我们正在获取数据,所以只期望有一个200响应。在响应中,我们还描述了内容类型,并将模式与使用$ref的组件的模式相匹配。
为了测试这一点。
- 确保开发服务器正在运行。
- 在你的浏览器中,刷新文档页面。
- 如果出现错误,请重新审视这些步骤。
否则,以下部分应该被添加到页面中。

获取todos路线的截图
要测试它,点击Try it out ,然后点击Execute ,然后检查服务器的响应。
获取单个todo (/todos/:id)
当获取单个todo时,我们要发送一个GET 请求到/todos/:id 。:id 是为动态id 。
为了记录这个路径,我们将编辑/docs/todos/get-todo.js 文件,如下所示。
module.exports = {
// operation's method
get: {
tags: ["Todo CRUD operations"], // operation's tag.
description: "Get a todo", // operation's desc.
operationId: "getTodo", // unique operation id
parameters: [
// expected params.
{
name: "id", // name of the param
in: "path", // location of the param
schema: {
$ref: "#/components/schemas/id", // data model of the param
},
required: true, // Mandatory param
description: "A single todo id", // param desc.
},
],
// expected responses
responses: {
// response code
200: {
description: "Todo is obtained", // response desc.
content: {
// content-type
"application/json": {
schema: {
$ref: "#/components/schemas/Todo", // todo data model
},
},
},
},
// response code
404: {
description: "Todo is not found", // response desc.
content: {
// content-type
"application/json": {
schema: {
$ref: "#/components/schemas/Error", // error data model
},
},
},
},
},
},
};
从上面来看,我们已经。
- 指定了操作的方法,
get。 - 定义了该操作的
tags。 - 用一个简短的
description和一个operationId来描述这个操作。 - 指定了该操作的参数。
我们描述了参数的name ,in ,可以是path,header,query, 或cookie 。在我们的例子中,它是path 。我们使用$ref ,将参数指向其对应的模式组件,指定它是required ,并给出参数的简短description 。
- 指定了预期的响应。对于这种情况,我们有两个。
200和404。如果找到了todo,它将返回200,否则404。对于每个响应,我们将给出一个简短的描述,阐述内容类型,并使用$ref将模式与它的组件等价物相匹配。
为了测试这一点。
- 确保开发服务器正在运行。
- 在你的浏览器中,刷新文档页面。
- 在出现错误的情况下,重温一下步骤。
以下部分应该被添加到页面中。

获取单一todo路线的截图
要试一下,从上一个操作中,得到一个id 。点击当前操作的Try it out 按钮,在参数部分粘贴id ,观察服务器的响应。
创建一个todo (/todos)
当创建一个todo时,我们要发送一个POST ,将todo的数据发送到/todos 。这些数据在requestBody 。
为了记录这个路径,我们需要编辑docs/todos/create-todo.js 文件,如下所示。
module.exports = {
// operation's method
post: {
tags: ["Todo CRUD operations"], // operation's tag
description: "Create todo", // short desc
operationId: "createTodo", // unique operation id
parameters: [], // expected params
requestBody: {
// expected request body
content: {
// content-type
"application/json": {
schema: {
$ref: "#/components/schemas/TodoInput", // todo input data model
},
},
},
},
// expected responses
responses: {
// response code
201: {
description: "Todo created successfully", // response desc
},
// response code
500: {
description: "Server error", // response desc
},
},
},
};
从上面来看,我们已经。
- 指定了操作的方法,
post。 - 指定了操作的
tags。 - 用一个简短的
description和一个operationId来描述该操作。 - 指定了操作的
parameters。对于这种情况,没有。 - 指定了
requestBody。通过它,我们指定了内容类型,并使用$ref,将模式与组件中的等价物相匹配。 - 指定了预期的响应。如果todo被成功创建,
201;如果有一个服务器错误,500。
为了测试这一点。
- 确保开发服务器正在运行。
- 在你的浏览器中,刷新文档页面。
- 在出现错误的情况下,重温一下步骤。
以下部分应该被添加到你的页面中。

创建todo路线的截图
为了测试功能,点击Try it out 按钮,在Request Body ,填写数据,点击Execute ,然后观察服务器的反应。
更新一个todo (/todos/:id)
当更新一个todo时,我们将发送一个PUT 请求到/todos/:id 。动态的id 是:id 。在这个API中,对todo的更新涉及到切换完成值。
为了记录这个路径,我们必须编辑docs/todos/update-todos.js 文件,如下所示。
module.exports = {
// operation's method
put: {
tags: ["Todo CRUD operations"], // operation's tag
description: "Update todo", // short desc
operationId: "updateTodo", // unique operation id
parameters: [
// expected params
{
name: "id", // name of param
in: "path", // location of param
schema: {
$ref: "#/components/schemas/id", // id model
},
required: true, // mandatory
description: "Id of todo to be updated", // short desc.
},
],
// expected responses
responses: {
// response code
200: {
description: "Todo updated successfully", // response desc.
},
// response code
404: {
description: "Todo not found", // response desc.
},
// response code
500: {
description: "Server error", // response desc.
},
},
},
};
从上面来看,我们已经。
- 指定了操作的方法,
put。 - 指定了操作的
tags。 - 用一个简短的
description和一个operationId来描述该操作。 - 指定了操作的参数。我们已经描述了
name,in,schema,required, 和description属性。通过schema,我们指出了使用$ref的等价组件。 - 指定了我们期望的不同响应。
200,如果一个todo被成功更新,404,如果没有找到该id的todo,以及500,如果有一个服务器错误更新todo。
要测试这个。
- 确保开发服务器正在运行。
- 在你的浏览器中,刷新文档页面。
- 在出现错误的情况下,重温一下步骤。
以下部分应该被添加到你的页面中。

更新todo路线的截图
要尝试一下,从第一个操作中得到一个todo的id ,点击Try it out 按钮,在参数部分粘贴id ,点击Execute ,观察服务器的反应。
删除一个todo(/todos/:id)
当删除一个todo时,我们发送一个DELETE 请求到/todos/:id 。动态id 是:id 。
为了记录这个路径,我们必须编辑/docs/todos/delete-todo.js 文件,如下所示。
module.exports = {
// operation's method.
delete: {
tags: ["Todo CRUD operations"], // operation's tag
description: "Deleting a todo", // short desc
operationId: "deleteTodo", // unique operation id
parameters: [
// expected parameters
{
name: "id", // name of param
in: "path", // location of param
schema: {
$ref: "#/components/schemas/id", // id model
},
required: true, // mandatory
description: "Deleting a done todo", // param desc
},
],
// expected responses
responses: {
// response code
200: {
description: "Todo deleted successfully", // response desc
},
// response code
404: {
description: "Todo not found", // response desc
},
// response code
500: {
description: "Server error", // response desc
},
},
},
};
从上面来看,我们已经。
- 指定了操作的方法,
delete。 - 指定了操作的
tags。 - 用简短的
description和operationId来描述该操作。 - 指定了
parameters。对于一个参数,我们描述了name,in,schema,required, 和description的属性。 - 指定了
responses。在这个操作中,如果todo被成功删除,我们可以得到一个200响应,如果没有找到带有该id的todo,则得到一个404响应,如果删除todo时出现服务器错误,则得到一个500响应。
要测试这一点。
- 确保开发服务器正在运行。
- 在你的浏览器中,刷新文档页面。
- 如果出现错误,请重温一下步骤。
否则,应该在你的页面上添加以下部分。

删除todo路线的截图
要尝试这个方法,获取更新的todo的id ,点击Try it out 按钮,在参数部分粘贴id ,点击Execute 按钮,然后观察服务器的反应。
结论
记录一个API是对该API可用性的一个优势,因为任何人都可以理解和使用它。
Swagger在记录RESTful API方面做了大量的工作。根据你正在构建的API,Swagger提供了大量的[功能]。