如何用 Swagger UI 和 JSDoc 编写 Express API 文档

Swagger 提供了一种用于展示这些文档的工具:Swagger UI。Swagger UI 可以根据 OpenAPI 规范定义创建一个网页。正如本教程将展示的那样,这些定义可以直接在 JSDoc 注释中使用 YAML 编写。

用 Apifox,节省研发团队的每一分钟

如何用 Swagger UI 和 JSDoc 编写 Express API 文档

免费使用 Apifox

相关推荐

最新文章

API

一体化协作平台

API 设计

API 文档

API 调试

自动化测试

API Mock

API Hub

立即体验 Apifox
目录
原文地址:https://dev.to/kabartolo/how-to-document-an-express-api-with-swagger-ui-and-jsdoc-50do  作者:Kate Bartolo


JSDoc 是一种流行的工具,用于从应用程序源代码的注释中生成文档。它有两个作用。首先,文档直接对查看源代码的任何人可见。其次,这些注释可以后期编译成完整的参考文档集。


Swagger 提供了一种用于展示这些文档的工具:Swagger UI。Swagger UI 可以根据 OpenAPI 规范定义创建一个网页。正如本教程将展示的那样,这些定义可以直接在 JSDoc 注释中使用 YAML 编写。


在本教程中,你将为 Express API 设置一个 Swagger UI 文档网页。然后,你可以在 API 的源代码中编写 JSDoc 注释以生成 OpenAPI 定义。最后,你将获得遵循 OpenAPI 规范的文档,并通过在 Express API 中添加自定义的/docs端点进行展示。

如何用 Swagger UI 和 JSDoc 编写 Express API 文档
Swagger

先决条件

要完成本教程,你需要:

  • 熟悉 REST API 和 Express
  • 在系统上安装 Node.js
  • 在本地 Express 服务器上运行的基于 Express 的 REST API。如果没有,你可以安装本教程中使用的 Express API。它从 JSONPlaceholder 获取用户数据。要安装和运行示例 Express API,请首先克隆存储库(将test-api替换为你选择的目录名称):
git clone https://github.com/kabartolo/jsonplaceholder-express-api test-api


接下来,运行以下命令启动 Express 服务器(将test-api替换为你刚创建的目录的名称):

cd test-api
npm install
npm run start


在浏览器中导航到localhost:3000以查看 API。你应该看到指向/users/users/1的链接。

启动 Express 服务器
启动 Express 服务器

导航到其中任何一个以查看来自 JSONPlaceholder 的用户数据。本教程中添加的代码可以在存储库的docs分支中找到。

术语

_OpenAPI_是规范的名称,而_Swagger_是实现该规范的一组工具。请参阅 理解 Swagger 和 OpenAPI:API 设计和文档化的最佳实践


本教程使用了由 OpenAPI 定义的以下与 API 相关的术语和定义:

    https://api.example.com/v1/users?role=admin&status=active
    \________________________/\____/ \______________________/
             服务器URL       端点      查询参数
                                路径
  • 服务器 URL 或基本 URL:所有 API 端点的基本 URL:localhost:3000example.com/api
  • 端点路径:表示资源位置的路径(相对于基本 URL):/users/users/1
  • 操作:用于操作端点路径的 HTTP 方法:GET、POST、PUT、DELETE
  • 资源:表示真实世界对象的信息(例如用户或书籍),通常由 API 作为 JSON 数据返回。在 Express 中由数据库模型表示。从 API 检索数据的完整 URL 是通过将端点添加到基本 URL 形成的:localhost:3000/users

步骤 1:设置应用程序

1.1:安装swagger-jsdocswagger-ui-express

要从 JSDoc 注释创建 Swagger UI 页面,你需要一种将文档传递给 Swagger UI 的方法:

  • swagger-jsdoc从 JSDoc 注释生成 OpenAPI 定义。
  • swagger-ui-express根据这些定义创建 Swagger UI 页面。要将swagger-jsdocswagger-ui-express安装到 Express API 中,请运行以下命令:
npm install swagger-jsdoc@5.0.1 --save-exact
npm install swagger-ui-express --save
本教程使用的是swagger-jsdoc版本5.0.1。最新版本可能与本教程不兼容。

1.2:创建 API 规范

Swagger UI 根据一组 OpenAPI 定义创建文档页面。这些定义使用 YAML JSON 编写,用于描述 REST API。有关 OpenAPI 规范的基本结构的更多信息,请参阅基本结构


在 Express API 的app.js文件中,在所需模块列表下添加以下代码:

// app.jsconst 
swaggerJSDoc = require('swagger-jsdoc');

const swaggerDefinition = {
  openapi: '3.0.0',
  info: {
    title: 'Express API for JSONPlaceholder',
    version: '1.0.0',
  },
};

const options = {
  swaggerDefinition,
  // 包含OpenAPI定义的文件路径apis: ['./routes/*.js'],
};

const swaggerSpec = swaggerJSDoc(options);

swaggerDefinition对象(即 OpenAPI 定义)定义了 API 的根信息。向swaggerDefinition提供一些基本信息,例如 API 的titleversion。稍后可以填写更多信息。


options对象包含swaggerDefinition对象和一个名为apis的路径数组。这些是包含其他 OpenAPI 定义的文件的路径。这些文件路径应相对于 Express API 的根目录。在我们的例子中,定义将直接在/routes文件中的 JSDoc 中编写。你可以逐个列出文件名,也可以使用通配符*添加目录中的所有 JavaScript 文件,如上所示。


options对象由swagger-jsdoc用于在名为swaggerSpec的变量中生成一个 OpenAPI 规范。此规范相当于 Swagger UI 通常用于创建文档页面的swagger.jsonswagger.yaml文件。你将在下一步中将此对象传递给 Swagger UI。


重新启动 Express 服务器以确保没有错误。如果在此阶段遇到任何错误,请检查你的swagger-jsdoc版本是否确切为5.0.1

1.3:创建 Swagger UI 文档页面

要为 Express API 创建 Swagger UI 页面,请在app.js文件中包含swagger-ui-express。然后,添加一个名为/docs(或你选择的任何名称)的端点路径:

// app.js
// ...
const swaggerJSDoc = require('swagger-jsdoc');
const swaggerUi = require('swagger-ui-express');

// ...

var app = express();

app.use('/docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec));

如上所示,swagger-ui-express提供了两个回调函数来设置端点:一个用于使用swaggerSpec定义设置 Swagger UI,另一个用于将其提供给/docs端点。


重新启动 Express 服务器,并在浏览器中导航到localhost:3000/docs


你将看到 Express API 的标题和版本号,以及 OpenAPI 版本号(3.0.0)。由于我们还没有其他定义,你将看到一个“在规范中未定义任何操作!”的消息:
现在,你已经拥有了一个漂亮的 API 文档页面的起点!本教程的其余部分将提供有关 OpenAPI 定义的基本介绍。

步骤 2:定义 API 的根信息

你已经创建了一个 Swagger UI 文档页面,并准备开始编写文档。但是,在此之前,你应该为 API 添加更多的根定义。


返回到app.js。请注意,info对象映射到 OpenAPI 的 Info 对象,用于定义 API 的标题、描述、服务器列表、联系信息和路径列表。


以下是一个更完整定义的示例:

// app.js
const swaggerDefinition = {
  openapi: "3.0.0",
  info: {
    title: "Express API for JSONPlaceholder",
    version: "1.0.0",
    description:
      "This is a REST API application made with Express. It retrieves data from JSONPlaceholder.",
    license: {
      name: "Licensed Under MIT",
      url: "https://spdx.org/licenses/MIT.html",
    },
    contact: {
      name: "JSONPlaceholder",
      url: "https://jsonplaceholder.typicode.com",
    },
  },
  servers: [
    {
      url: "http://localhost:3000",
      description: "Development server",
    },
  ],
};

如果有生产服务器,请将 URL 和描述添加到servers列表中。有关可以添加到根定义的其他属性的更多信息,请参阅基本结构


OpenAPI 文档中,你会注意到还有一个paths字段。你不需要在此处指定路径定义,因为每个路径都在单独的 JSDoc 注释中定义(将在下一步中添加)。这些路径定义将由swagger-jsdoc编译成一个paths对象。


重新启动 Express 服务器,并在浏览器中导航到localhost:3000/docs
你应该在文档页面顶部看到有关 API 的更多信息:

重新启动 Express 服务器
重新启动 Express 服务器

现在,你可以开始记录 Express 路由。

步骤 3:编写文档

/docs端点处有一个 Swagger UI 文档页面,并且你已经拥有了 API 的完整根信息,现在可以开始编写路径定义了。每个路径定义对应于 API 中的一个 Express 路由。它描述了操作和端点路径,例如GET /usersDELETE /users/:id

3.1:记录路由

要记录/routes/users.js,首先在第一个路由上方添加一个以@swagger开头的注释。然后,添加一些关于路由的基本信息:

// routes/users.js

/**
 * @swagger
 * /users:
 *   get:
 *     summary: Retrieve a list of JSONPlaceholder users
 *     description: Retrieve a list of users from JSONPlaceholder. Can be used to populate a list of fake users when prototyping or testing an API.
 */
router.get("/", function (req, res) {
  //...
});

请注意,swagger-jsdoc会查找带有@swagger@openapi标签的注释来创建 OpenAPI 定义。


如代码示例所示,添加端点路径/users和操作get(缩进两个空格)。Express 路由函数get('/')中的路径是相对于/users的,因此定义中的路径应为/users


summary应该是对此路由目标的简要描述。description应提供更多详细信息,例如何时或为何要使用该路由。

请确保使用两个空格(或四个空格)进行缩进,而不是制表符。有关更多信息,请参阅 YAML 语法


重新启动 Express 服务器,并在浏览器中导航到localhost:3000/docs
你应该在页面底部看到GET /users的列表:

Swagger 记录路由
记录路由

3.2:记录响应

当此 GET 请求成功(即状态码为200)时,用户将想要知道返回了什么。要定义一个成功的响应,请将responses对象和一个名为200的响应添加到路径定义中:

// routes/users.js

/**
 * @swagger
 * /users:
 *   get:
 *     summary: Retrieve a list of JSONPlaceholder users.
 *     description: Retrieve a list of users from JSONPlaceholder. Can be used to populate a list of fake users when prototyping or testing an API.
 *     responses:
 *       200:
 *         description: A list of users.
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 data:
 *                   type: array
 *                   items:
 *                     type: object
 *                     properties:
 *                       id:
 *                         type: integer
 *                         description: The user ID.
 *                         example: 0
 *                       name:
 *                         type: string
 *                         description: The user's name.
 *                         example: Leanne Graham
 */
router.get("/", function (req, res) {
  //...
});

description字段描述了响应或返回的内容。content字段描述了内容类型(application/json),而schema描述了响应对象。在我们的例子中,JSONPlaceholder 返回一个带有data字段的对象,该字段包含你请求的数据。对于这个响应,data包含一个用户对象数组。为了避免文件混乱,现在只添加一个或两个用户属性(例如idname)。


为每个属性添加一个真实的示例值(例如'Leanne Graham');否则,Swagger UI 会创建一个通用示例,例如'string'

注意在此模式中如何定义类型。例如,要定义一个数组,添加type: array和一个items字段。在数据类型文档中了解更多关于类型的信息。


你也可以使用这种方式描述错误响应。有关描述每个响应可用字段的更多详细信息,请参阅 Swagger 的描述响应文档。


重新启动 Express 服务器,然后再次在浏览器中导航到localhost:3000/docs。你应该看到响应,一个示例值(使用你为每个属性提供的示例值),以及此响应返回的数据的模式:

Swagger 记录响应
记录响应

接下来,通过添加我们已经涵盖的字段(summarydescriptionresponses)来定义GET /users/:id路径:

// routes/users.js

/**
 * @swagger
 * /users/{id}:
 *   get:
 *     summary: Retrieve a single JSONPlaceholder user.
 *     description: Retrieve a single JSONPlaceholder user. Can be used to populate a user profile when prototyping or testing an API.
 *     responses:
 *       200:
 *         description: A single user.
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 data:
 *                   type: object
 *                   properties:
 *                     id:
 *                       type: integer
 *                       description: The user ID.
 *                       example: 0
 *                     name:
 *                       type: string
 *                       description: The user's name.
 *                       example: Leanne Graham
 */

router.get("/:id", function (req, res) {
  //...
});

在这里,路径参数(id)被添加到端点路径中:/users/{id}。花括号({})用于标记端点路径中的路径参数。请注意,冒号样式(/users/:id)在 Swagger 中不起作用。


这个schema中的data对象包含一个单独的用户对象,而不是一个用户对象数组,但属性是相同的。


接下来,通过添加我们已经涵盖的字段(summarydescriptionresponses)来定义POST /users路径:

// routes/users.js

/**
 * @swagger
 * /users:
 *   post:
 *     summary: Create a JSONPlaceholder user.
 *     responses:
 *       201:
 *         description: Created
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 data:
 *                   type: object
 *                   properties:
 *                     id:
 *                       type: integer
 *                       description: The user ID.
 *                       example: 0
 *                     name:
 *                       type: string
 *                       description: The user's name.
 *                       example: Leanne Graham
 */
router.post("/", function (req, res) {
  // ...
});

在这种情况下,成功的响应是201。它返回一个带有包含新用户的data字段的对象。


你可以继续以相同的方式为剩余的路径定义添加路径定义。我们将在后面的步骤中进行一些重构。


重新启动 Express 服务器,然后再次在浏览器中导航到localhost:3000/docs。现在,你将看到GET /users/{id}POST /users和你添加的任何其他路径定义的列表:

Swagger 记录响应
记录响应

3.3:文档化请求

你还可以在 OpenAPI 定义中文档化请求数据,例如参数和请求体。例如,GET /users/:id具有一个id参数,应该进行文档化。


要文档化参数,请在路径定义中添加一个parameters字段:

// routes/users.js

/**
 * @swagger
 * /users/{id}:
 *   get:
 *     summary: Retrieve a single JSONPlaceholder user.
 *     description: Retrieve a single JSONPlaceholder user. Can be used to populate a user profile when prototyping or testing an API.
 *     parameters:
 *       - in: path
 *         name: id
 *         required: true
 *         description: Numeric ID of the user to retrieve.
 *         schema:
 *           type: integer
 *     responses:
 *       200:
 *         ...
 */
router.get("/:id", function (req, res) {
  //...
});

在此参数的定义中,in定义了参数的位置(在这种情况下,它是路径参数,因为它是路径的一部分)。你还可以添加namedescriptionschema以及参数是否required。有关更多详细信息,请参阅描述参数


重新启动 Express 服务器,然后再次在浏览器中导航到localhost:3000/docs。你将看到此路由的参数列表:

Swagger 文档化请求
文档化请求

接下来,为POST /users文档化请求体,以描述在数据库中创建新用户所需的数据。为此,请在此路径定义中添加一个requestBody字段:

// routes/users.js

/**
 * @swagger
 * /users:
 *   post:
 *     summary: Create a JSONPlaceholder user.
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *             properties:
 *               name:
 *                 type: string
 *                 description: The user's name.
 *                 example: Leanne Graham
 *     responses:
 *       201:
 *         ...
 */
router.post("/", function (req, res) {
  // ...
});

这将在此路径定义中添加一个请求体模式。此示例显示可以在请求体中发送name。你可以稍后为新用户添加更多属性。有关更多详细信息,请参阅描述请求体


重新启动 Express 服务器,然后再次在浏览器中导航到localhost:3000/docs。你将看到一个名为Request body的部分,其中包含你提供的模式:

Swagger 文档化请求
文档化请求

3.4:文档化资源

你可能已经注意到,到目前为止,在文档中重复了用户模式多次。为了避免这种重复,你可以在一个地方定义用户模式,并从其他地方引用它。


你 Express API 定义的每个模型都可以作为一个单独的模式定义(或组件)进行文档化。为了为用户模型做到这一点,请在文件顶部的components/schemas下添加一个User模式定义:

// routes/users.js

/**
 * @swagger
 * components:
 *   schemas:
 *     User:
 *       type: object
 *       properties:
 *         id:
 *           type: integer
 *           description: The user ID.
 *           example: 0
 *         name:
 *           type: string
 *           description: The user's name.
 *           example: Leanne Graham
 */

然后,你可以使用$ref引用此模式定义:

// routes/users.js

/**
 * @swagger
 * /users:
 *   get:
 *     summary: Retrieve a list of JSONPlaceholder users
 *     description: Retrieve a list of users from JSONPlaceholder. Can be used to populate a list of fake users when prototyping or testing an API.
 *     responses:
 *       200:
 *         description: A list of users.
 *         content:
 *           application/json:
 *             schema:
 *               type: array
 *               items:
 *                 $ref: '#/components/schemas/User'
 */
router.get("/", function (req, res) {
  //...
});

$ref路径使用 JSON 引用表示法。#符号表示当前文档的根,然后按顺序解析剩余的嵌套值。有关更多信息,请参阅使用$ref


重新启动 Express 服务器,并再次在浏览器中导航到localhost:3000/docs。你将在POST /users的请求体定义中看到你的NewUser模式:

Swagger NewUser模式
NewUser模式

这涵盖了使用 JSDoc 注释生成 OpenAPI 定义的基本技术。

总结

你现在已经准备好为 Express API 生成完整的参考文档页面。你已经创建了一组基本的 OpenAPI 定义和一个显示它们的 Swagger UI 页面。如果你想要更多练习 OpenAPI 规范,你可以完成文档化jsonplaceholder-express-api


本教程还介绍了编写 OpenAPI 定义的基础知识。要完成你的文档,请参阅 OpenAPI 规范 Swagger 文档

使用 Apifox 管理 API 文档

Swagger 管理接口有时很不方便,缺乏团队间的分享协作,所以我更推荐使用 Apifox


Apifox 是一个比 Postman 更强大的接口测试工具,Apifox = Postman + Swagger + Mock + JMeter,Apifox 支持调试 http(s)、WebSocket、Socket、gRPC、Dubbo 等协议的接口,并且集成了 IDEA 插件。在开发完接口后,可以通过 Apifox 的 IDEA 插件一键生成接口文档,多端同步,非常方便测试和维护。

将 Swagger 导出为 JSON

如下图所示,选择“Convert and save as JSON”,将 Swagger 文档导出为 JSON 文件。

将 Swagger 导出为 JSON
将 Swagger 导出为 JSON

将 Swagger 文件导入 Apifox

打开 Apifox,创建一个项目后,选择“项目设置->导入数据->OpenAPI/Swagger->文件导入”,将已导出的 Swagger 格式的 JSON 文件导入即可。

导出的 Swagger 格式的 JSON 文件导入 Apifox
导出的 Swagger 格式的 JSON 文件导入 Apifox 

导入时,会有预览,可以选择导入全部,也可以选择性的导入接口。

Apifox 选择导入接口
Apifox 选择导入接口

导入成功之后,就可以选择一个环境来测试接口。如下图所示,接口成功返回数据:

Apifox 导入 Swagger 文件
导入成功


知识扩展: