You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js集成Swagger遇“No operations defined in spec!”及components为空问题

问题排查与解决方法

问题原因

  1. API文件路径匹配失败
    swagger.util.js位于src/utils目录,配置的apis: ["../routes/*.js"]是相对当前文件的路径,但swagger-jsdoc的glob路径解析基于项目启动时的工作目录(通常是项目根目录),而非当前JS文件所在目录。此时../routes/*.js会被解析为项目根目录下的routes/*.js,但实际路由文件在src/routes下,导致无法找到目标文件,无法读取Swagger注释。

  2. 缺少接口操作的Swagger注释
    user.route.js中仅定义了components.schemas,但没有为/register接口添加操作级别的Swagger注释(比如@swagger的POST请求定义)。swagger-jsdoc需要明确的操作注释来生成paths字段,未被引用的schemas也可能不会被自动纳入specs。

解决方法

1. 修复API文件路径(使用绝对路径)

修改swagger.util.js,借助Node.js的path模块生成绝对路径,确保swagger-jsdoc能准确找到路由文件:

import swaggerJSDoc from "swagger-jsdoc";
import path from "path";

const options = {
    failOnErrors: true,
    definition: {
        openapi: "3.0.0",
        info: {
            title: "API",
            version: "1.0.0",
            description: "Endpoints"
        },
        servers: [
            {
                url: "http://localhost:80",
                description: "HTTP"
            },
            {
                url: "http://localhost:443",
                description: "HTTPS"
            }
        ],
    },
    // 生成绝对路径,适配ES模块环境
    apis: [path.resolve(path.dirname(import.meta.url).slice(7), "../routes/*.js")]
};

const specs = swaggerJSDoc(options);

export default specs;

注:import.meta.url返回当前文件的file://格式URL,slice(7)移除前缀后,用path.dirname获取目录,再拼接路由路径。如果是CommonJS环境(使用require),可直接用__dirname替代path.dirname(import.meta.url).slice(7)。

2. 添加接口操作的Swagger注释

在user.route.js的POST接口上方添加操作注释,同时引用已定义的UserAccount schema:

import express from "express";
import trimRequest from "trim-request";

import { register } from "../controllers/user.controller.js";

const router = express.Router();

/**
 * @swagger
 * components:
 *   schemas:
 *     UserAccount:
 *       type: object
 *       required:
 *         - username
 *         - email
 *         - password
 *       properties:
 *         username:
 *           type: string
 *         email:
 *           type: string
 *         password:
 *           type: string
 *       example:
 *         username: Test
 *         email: test@test.com
 *         password: TestTest1!
 */

/**
 * @swagger
 * /api/v1/register:
 *   post:
 *     summary: 用户注册
 *     tags: [用户]
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             $ref: '#/components/schemas/UserAccount'
 *     responses:
 *       200:
 *         description: 注册成功
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 message:
 *                   type: string
 *                 user:
 *                   $ref: '#/components/schemas/UserAccount'
 *       400:
 *         description: 输入参数错误
 */
router.route("/register").post(trimRequest.all, register);

export default router;

注意:接口路径/api/v1/register要与app.js中注册的路由前缀/api/v1保持一致,否则Swagger文档中路径会不匹配。

3. 验证路径正确性(可选)

可在swagger.util.js中打印生成的绝对路径,确认是否指向正确文件:

const apiPath = path.resolve(path.dirname(import.meta.url).slice(7), "../routes/*.js");
console.log("API文件路径:", apiPath); // 应输出类似:/项目根目录/src/routes/*.js

完成修改后重启项目,控制台打印的specs会包含components和paths字段,Swagger文档也会显示对应的接口操作。

内容的提问来源于stack exchange,提问作者GenesysRTA

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 06:41:05