Node.js集成Swagger遇“No operations defined in spec!”及components为空问题
问题原因
API文件路径匹配失败
swagger.util.js位于src/utils目录,配置的apis: ["../routes/*.js"]是相对当前文件的路径,但swagger-jsdoc的glob路径解析基于项目启动时的工作目录(通常是项目根目录),而非当前JS文件所在目录。此时../routes/*.js会被解析为项目根目录下的routes/*.js,但实际路由文件在src/routes下,导致无法找到目标文件,无法读取Swagger注释。缺少接口操作的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

