使用 Swagger 记录 Node.js API

2025-06-04

使用 Swagger 记录 Node.js API

介绍

API 文档是软件开发不可或缺的一部分。它是一份说明手册,解释了如何使用 API 及其服务。该手册可能包含教程、代码示例、屏幕截图以及任何其他有助于用户更好地理解如何使用 API 的内容。

在本文中,我们将学习如何使用名为 Swagger 的工具为用 Node.js 编写的 API 编写文档。Swagger 允许您描述 API 的结构,以便机器可以读取它们。API 描述自身结构的能力是 Swagger 所有优点的根源。为什么它这么棒?因为通过读取 API 的结构,Swagger 可以自动构建美观且交互式的 API 文档。它还可以自动为您的 API 生成多种语言的客户端库,并探索其他可能性,例如自动化测试。Swagger 通过要求 API 返回包含整个 API 详细描述的 YAML 或 JSON 来实现这一点。此文件本质上是符合OpenAPI 规范API 资源清单。

使用 Node.js 和 Express 构建我们的 API

要开始编写 API 规范,我们将使用 Node.js 构建 API。Node.js 是一个后端 JavaScript 运行时环境,运行在 V8 JavaScript 引擎上,并在 Web 浏览器之外执行 JavaScript 代码。为了简单起见,我已经设置好了项目,您可以从这个GitHub仓库克隆它。为了在本地机器上运行后端,我们将遵循以下步骤:

  • 为项目创建一个新文件夹,并在根文件夹中运行此命令来克隆存储库
git clone https://github.com/DesmondSanctity/node-js-swagger.git
Enter fullscreen mode Exit fullscreen mode
  • 要成功运行代码,我们需要一个数据库连接。我使用了 MongoDB Atlas 集群作为数据库,我们可以按照本教程进行设置,设置过程非常简单。设置完成后,我们将获取 URL,这就是我们从应用程序连接到数据库所需的全部内容。
  • 我们使用 JSON Web Token (JWT) 来验证 API 的访问权限,因此我们将生成一个密钥,供我们的应用发送和验证请求。为了生成密钥,我们将在终端的任意位置运行此命令。此脚本将生成一个随机的 64 位 ASCII 字符串,可用于加密 JWT 令牌。
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
Enter fullscreen mode Exit fullscreen mode
  • 现在,我们将创建一个名为的文件.env,并将 MongoDB Atlas 集群 URL 和 JWT 密钥作为环境变量存储。该文件应如下所示:
    JWT_SECRET=<your JWT secret>
    ATLAS_URI=<your MongoDB Atlas cluster URL>
Enter fullscreen mode Exit fullscreen mode
  • 现在,我们准备运行该应用程序,但首先,我们将安装一些软件包,然后启动该应用程序。如果您之前克隆了GitHub仓库,则只需运行以下命令:
    npm install   // To install the neccessary packages
    npm start    //  To start the application
Enter fullscreen mode Exit fullscreen mode
  • 如果此时成功,您将在终端中看到以下消息
    > mini-blog@1.0.0 start
    > nodemon server.js

    [nodemon] 2.0.20
    [nodemon] to restart at any time, enter `rs`
    [nodemon] watching path(s): *.*
    [nodemon] watching extensions: js,mjs,json
    [nodemon] starting `node server.js`
    Database Connected
    Server connected to http://localhost:8080
Enter fullscreen mode Exit fullscreen mode

添加 Swagger UI 和配置

现在我们已经准备好 API,我们将开始为其定义 Swagger 规范。我们可以通过两种方式为 API 构建 Swagger 文档:

  • 在我们的应用程序中将规格手动写入路由器文件或专用的 json 或 yaml 文件中。
  • 使用现有的开发人员工具或包自动生成文档。

在本教程中,我们将使用手动方法来确保定义和规范的准确性。首先,我们将使用以下命令安装两个名为"swagger-jsdoc"和 的包作为依赖项:"swagger-ui-express"

npm install swagger-jsdoc swagger-ui-express --save-dev
Enter fullscreen mode Exit fullscreen mode

安装完成后,我们将swagger.js在应用程序的根目录中创建一个名为的新文件,并将以下代码粘贴到其中

    import swaggerJsdoc from 'swagger-jsdoc'
    import swaggerUi from 'swagger-ui-express'
    const options = {
      definition: {
        openapi: '3.0.0',
        info: {
          title: 'Mini Blog API',
          description: "API endpoints for a mini blog services documented on swagger",
          contact: {
            name: "Desmond Obisi",
            email: "info@miniblog.com",
            url: "https://github.com/DesmondSanctity/node-js-swagger"
          },
          version: '1.0.0',
        },
        servers: [
          {
            url: "http://localhost:8080/",
            description: "Local server"
          },
          {
            url: "<your live url here>",
            description: "Live server"
          },
        ]
      },
      // looks for configuration in specified directories
      apis: ['./router/*.js'],
    }
    const swaggerSpec = swaggerJsdoc(options)
    function swaggerDocs(app, port) {
      // Swagger Page
      app.use('/docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec))
      // Documentation in JSON format
      app.get('/docs.json', (req, res) => {
        res.setHeader('Content-Type', 'application/json')
        res.send(swaggerSpec)
      })
    }
    export default swaggerDocs
Enter fullscreen mode Exit fullscreen mode

我们可以从代码中看到,我们定义了将用于文档的开放 API 规范 (OAS):有关 API 的信息或详细信息、我们将其公开给的服务器以及 Swagger 应该在我们的应用程序中查找每个 API 的规范的路由。

我们还可以看到我们的swaggerDocs函数,它允许应用程序实例和端口使用我们之前安装的swaggerUiswaggerJsdoc包生成文档,并在路由中提供服务/docs。我们还可以使用 获取 JSON 格式/docs.json。最后,我们将更新server.js文件以包含我们的swaggerDocs函数,以便在每次运行项目时始终生成和更新文档。

在为每个端点写出规范之前的最后一步是将swaggerDocs函数添加到我们的server.js文件中,以便我们在应用程序启动时启动 swagger。

    import express from 'express';
    import cors from 'cors';
    import morgan from 'morgan';
    import dotenv from 'dotenv';
    import connect from './database/conn.js';
    import userRouter from './router/user.js';
    import postRouter from './router/post.js';
    import swaggerDocs from './swagger.js'

    dotenv.config()
    const app = express();
    /** middlewares */
    app.use(express.json());
    app.use(cors());
    app.use(morgan('tiny'));
    app.disable('x-powered-by'); // less hackers know about our stack

    const port = process.env.PORT || 8080;
    /** HTTP GET Request */
    app.get('/', (req, res) => {
        res.status(201).json("Home GET Request");
    });

    /** api routes */
    app.use('/api/user', userRouter)
    app.use('/api/post', postRouter)
    /** start server only when we have valid connection */
    connect().then(() => {
        try {
            app.listen(port, () => {
                console.log(`Server connected to http://localhost:${port}`);
            })
            swaggerDocs(app, port)
        } catch (error) {
            console.log('Cannot connect to the server')
        }
    }).catch(error => {
        console.log("Invalid database connection...!");
    })
Enter fullscreen mode Exit fullscreen mode

编写我们的 API 规范

现在进入正题,我们将编写 Swagger 用来生成文档的 API 规范。目前,我们的应用中有两个控制器和路由器文件,分别用于userpost。控制器包含应用的逻辑,而路由器则以请求的形式将端点和负载传递给控制器​​。现在,我们开始定义规范吧!

对于用户路由器,我们将首先导入路由器文件中需要的包user.js

    import { Router } from "express";
    const userRouter = Router();
    /** import all controllers */
    import * as controller from '../controllers/userController.js';
    import Auth from '../middleware/auth.js';

    /** All the API routes comes here*/

    export default userRouter;
Enter fullscreen mode Exit fullscreen mode

然后,我们将为每种请求类型(即 GET、POST、PUT 和 DELETE)编写规范。该规范是一个 yaml 文件,嵌入在我们要记录的路由的开头。需要注意的一些要点如下:

  • 开放API规范实例——写在yaml文件的开头。
  • API 端点——我们将用于请求的 URL。
  • 请求类型——指示它是 GET、POST、PUT 还是 DELETE 请求。
  • 请求正文——用于将我们的有效负载传递给 API。
  • 参数——我们通过 URL 或参数传递给后端的数据
  • 内容类型——我们发送的内容类型。它会被传递到 HTTP 标头。
  • 模式——它包含我们的请求主体的类型、必需的字段以及请求主体可以接受的属性。
  • 响应——我们进行的 API 调用的结果,它告诉我们调用是否失败或成功,并报告错误。

邮政:

    /** POST Methods */
    /**
     * @openapi
     * '/api/user/register':
     *  post:
     *     tags:
     *     - User Controller
     *     summary: Create a user
     *     requestBody:
     *      required: true
     *      content:
     *        application/json:
     *           schema:
     *            type: object
     *            required:
     *              - username
     *              - email
     *              - password
     *            properties:
     *              username:
     *                type: string
     *                default: johndoe 
     *              email:
     *                type: string
     *                default: johndoe@mail.com
     *              password:
     *                type: string
     *                default: johnDoe20!@
     *     responses:
     *      201:
     *        description: Created
     *      409:
     *        description: Conflict
     *      404:
     *        description: Not Found
     *      500:
     *        description: Server Error
     */
    userRouter.route('/register').post(controller.register); // register user

    /**
     * @openapi
     * '/api/user/login':
     *  post:
     *     tags:
     *     - User Controller
     *     summary: Login as a user
     *     requestBody:
     *      required: true
     *      content:
     *        application/json:
     *           schema:
     *            type: object
     *            required:
     *              - username
     *              - password
     *            properties:
     *              username:
     *                type: string
     *                default: johndoe
     *              password:
     *                type: string
     *                default: johnDoe20!@
     *     responses:
     *      201:
     *        description: Created
     *      409:
     *        description: Conflict
     *      404:
     *        description: Not Found
     *      500:
     *        description: Server Error
     */
    userRouter.route('/login').post(controller.verifyUser,controller.login); // login in app

    /**
     * @openapi
     * '/api/user/verify':
     *  post:
     *     tags:
     *     - User Controller
     *     summary: Verify a user
     *     requestBody:
     *      required: true
     *      content:
     *        application/json:
     *           schema:
     *            type: object
     *            required:
     *              - username
     *            properties:
     *              username:
     *                type: string
     *                default: johndoe
     *     responses:
     *      201:
     *        description: Created
     *      409:
     *        description: Conflict
     *      404:
     *        description: Not Found
     *      500:
     *        desccription: Server Error
     */
    userRouter.route('/verify').post(controller.verifyUser, (req, res) => res.end()); // authenticate user
Enter fullscreen mode Exit fullscreen mode

得到:

    /** GET Methods */
    /**
     * @openapi
     * '/api/user/{username}':
     *  get:
     *     tags:
     *     - User Controller
     *     summary: Get a user by username
     *     parameters:
     *      - name: username
     *        in: path
     *        description: The username of the user
     *        required: true
     *     responses:
     *      200:
     *        description: Fetched Successfully
     *      400:
     *        description: Bad Request
     *      404:
     *        description: Not Found
     *      500:
     *        description: Server Error
     */
    userRouter.route('/:username').get(controller.getUser) // user with username
Enter fullscreen mode Exit fullscreen mode

放:

/** PUT Methods */
    /**
     * @openapi
     * '/api/user/update':
     *  put:
     *     tags:
     *     - User Controller
     *     summary: Modify a user
     *     requestBody:
     *      required: true
     *      content:
     *        application/json:
     *           schema:
     *            type: object
     *            required:
     *              - userId
     *            properties:
     *              userId:
     *                type: string
     *                default: ''
     *              firstName:
     *                type: string
     *                default: ''
     *              lastName:
     *                type: string
     *                default: ''
     *     responses:
     *      200:
     *        description: Modified
     *      400:
     *        description: Bad Request
     *      404:
     *        description: Not Found
     *      500:
     *        description: Server Error
     */
    userRouter.route('/update').put(controller.updateUser); // is use to update the user profile
Enter fullscreen mode Exit fullscreen mode

删除:

/** DELETE Methods */
    /**
     * @openapi
     * '/api/user/{userId}':
     *  delete:
     *     tags:
     *     - User Controller
     *     summary: Delete user by Id
     *     parameters:
     *      - name: userId
     *        in: path
     *        description: The unique Id of the user
     *        required: true
     *     responses:
     *      200:
     *        description: Removed
     *      400:
     *        description: Bad request
     *      404:
     *        description: Not Found
     *      500:
     *        description: Server Error
     */
    userRouter.route('/:userId').delete(controller.deleteUser);
Enter fullscreen mode Exit fullscreen mode

在 Swagger 上测试我们的 API

完成 API 文档后,我们应该能够查看 Swagger 文档,并使用它测试 API。如果您坚持到现在,应该会看到类似下图的视图。我们的文档已在/docs路由中提供。

Swagger UI 文档

我们将使用 Swagger 文档 UI 提出一些请求并查看结果。

要创建用户:

创建用户的 POST 请求

要创建帖子:

创建帖子的 POST 请求

从上面的示例可以看出,我们可以使用 Swagger 文档来测试我们的 API,例如在数据库中创建、读取和修改数据。这有助于使 API 易于理解和集成。按照这些示例,我们可以继续测试其他请求方法,例如使用 PUT 更新用户或帖子、使用 GET 读取用户或帖子,以及使用 DELETE 从数据库中删除它们。

结论

我们最终可以得出结论:API 文档是软件开发周期中非常重要的一部分,它有助于协作并使用户体验更加无缝衔接。Swagger 的优势包括但不限于:

  • 以相同的速度将 API 文档与服务器和客户端同步。
  • 允许我们生成 REST API 文档并与 REST API 交互。使用 Swagger UI 框架与 REST API 交互,可以清晰地了解 API 如何响应参数。
  • 提供 JSON 和 XML 格式的响应。
  • 有多种技术可供实施。
文章来源:https://dev.to/desmondsanctity/documenting-nodejs-api-using-swagger-4klp
PREV
现代前端开发人员必须具备的 7 项技能 1). HTML、CSS 和 JavaScript 2). Git 3). 响应式设计 4). 测试驱动开发 5). JavaScript 库/框架 6). 服务器端渲染/脚本的基础知识 7). 人际交往能力
NEXT
编码概念!圈复杂度