下面详细介绍 Swagger 在 Node.js 项目中的安装和完整使用方法,生成可视化的 API 文档界面。
📦 第一步:安装 Swagger 依赖
bash
npm install swagger-jsdoc swagger-ui-express
- swagger-jsdoc:将 JSDoc 注释转换为 Swagger/OpenAPI 规范
- swagger-ui-express:提供 Swagger UI 界面
⚙️ 第二步:配置 Swagger
创建 src/config/swagger.js:
javascript
// src/config/swagger.js
const swaggerJsdoc = require('swagger-jsdoc')
const options = {
definition: {
openapi: '3.0.0',
info: {
title: '用户管理 API 文档',
version: '1.0.0',
description: '基于 Express + JWT 的用户管理接口文档',
contact: {
name: 'API Support',
email: 'support@example.com',
},
license: {
name: 'MIT',
url: 'https://opensource.org/licenses/MIT',
},
},
servers: [
{
url: 'http://localhost:3000/api',
description: '开发服务器',
},
{
url: 'https://api.example.com/api',
description: '生产服务器',
},
],
components: {
securitySchemes: {
bearerAuth: {
type: 'http',
scheme: 'bearer',
bearerFormat: 'JWT',
description: '输入 Bearer Token',
},
},
schemas: {
// 通用响应格式
ApiResponse: {
type: 'object',
properties: {
code: {
type: 'integer',
description: '状态码:0-成功,其他-失败',
example: 0,
},
msg: {
type: 'string',
description: '响应消息',
example: '操作成功',
},
data: {
type: 'object',
description: '响应数据',
},
},
},
// 登录请求
LoginRequest: {
type: 'object',
required: ['username', 'password'],
properties: {
username: {
type: 'string',
description: '用户名',
example: 'admin',
},
password: {
type: 'string',
description: '密码',
example: '123456',
},
},
},
// 登录响应
LoginResponse: {
type: 'object',
properties: {
code: { type: 'integer', example: 0 },
msg: { type: 'string', example: '登录成功' },
data: {
type: 'object',
properties: {
token: {
type: 'string',
description: 'JWT Token',
example: 'eyJhbGciOiJIUzI1NiIs...',
},
userInfo: {
type: 'object',
properties: {
id: { type: 'integer', example: 1 },
username: { type: 'string', example: 'admin' },
email: { type: 'string', example: 'admin@example.com' },
role: { type: 'string', example: 'admin' },
status: { type: 'integer', example: 1 },
},
},
},
},
},
},
// 用户列表响应
UserListResponse: {
type: 'object',
properties: {
code: { type: 'integer', example: 0 },
msg: { type: 'string', example: '获取用户列表成功' },
data: {
type: 'object',
properties: {
total: { type: 'integer', example: 5 },
rows: {
type: 'array',
items: {
type: 'object',
properties: {
id: { type: 'integer' },
username: { type: 'string' },
email: { type: 'string' },
role: { type: 'string' },
status: { type: 'integer' },
createTime: { type: 'string' },
lastLogin: { type: 'string' },
},
},
},
page: { type: 'integer', example: 1 },
size: { type: 'integer', example: 10 },
totalPages: { type: 'integer', example: 1 },
},
},
},
},
// 用户信息
User: {
type: 'object',
properties: {
id: { type: 'integer' },
username: { type: 'string' },
email: { type: 'string' },
role: { type: 'string' },
status: { type: 'integer' },
createTime: { type: 'string' },
lastLogin: { type: 'string' },
},
},
// 创建用户请求
CreateUserRequest: {
type: 'object',
required: ['username', 'email'],
properties: {
username: { type: 'string', example: 'newuser' },
email: { type: 'string', example: 'newuser@example.com' },
role: { type: 'string', enum: ['admin', 'manager', 'user', 'developer'], example: 'user' },
},
},
},
},
security: [
{
bearerAuth: [],
},
],
tags: [
{
name: '认证',
description: '用户认证相关接口',
},
{
name: '用户管理',
description: '用户管理相关接口',
},
],
},
apis: ['./src/routes/*.js'], // 扫描所有路由文件中的 JSDoc 注释
}
module.exports = swaggerJsdoc(options)
🚀 第三步:在 app.js 中集成 Swagger
修改 src/app.js:
javascript
// src/app.js
const express = require('express')
const cors = require('cors')
require('dotenv').config()
const swaggerUi = require('swagger-ui-express')
const swaggerSpec = require('./config/swagger')
// 导入路由
const authRoutes = require('./routes/auth')
const userRoutes = require('./routes/user')
const app = express()
const PORT = process.env.PORT || 3000
// 中间件
app.use(cors())
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
// ===== 添加 Swagger UI =====
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec, {
explorer: true, // 显示搜索框
customCss: '.swagger-ui .topbar { display: none }', // 隐藏顶部栏
customSiteTitle: '用户管理 API 文档',
swaggerOptions: {
persistAuthorization: true, // 持久化认证信息
},
}))
// 导出 Swagger 规范(可选,用于其他工具)
app.get('/api-docs.json', (req, res) => {
res.setHeader('Content-Type', 'application/json')
res.send(swaggerSpec)
})
// 路由
app.use('/api/auth', authRoutes)
app.use('/api/user', userRoutes)
// 健康检查
app.get('/health', (req, res) => {
res.json({
status: 'ok',
timestamp: new Date().toISOString(),
uptime: process.uptime(),
})
})
// 404 处理
app.use((req, res) => {
res.status(404).json({
code: 404,
msg: '接口不存在',
data: null,
})
})
// 全局错误处理
app.use((err, req, res, next) => {
console.error('全局错误:', err)
res.status(500).json({
code: 500,
msg: err.message || '服务器内部错误',
data: null,
})
})
app.listen(PORT, () => {
console.log(`🚀 服务器已启动`)
console.log(`📍 地址: http://localhost:${PORT}`)
console.log(`📚 Swagger 文档: http://localhost:${PORT}/api-docs`)
console.log(`🌿 环境: ${process.env.NODE_ENV || 'development'}`)
})
📝 第四步:在路由中添加 Swagger 注释
1. 认证路由注释
修改 src/routes/auth.js,添加 JSDoc 注释:
javascript
// src/routes/auth.js
const express = require('express')
const router = express.Router()
const jwt = require('jsonwebtoken')
const bcrypt = require('bcryptjs')
const { findUserByUsername } = require('../utils/mockData')
/**
* @swagger
* /auth/login:
* post:
* summary: 用户登录
* description: 使用用户名和密码登录,返回 JWT Token
* tags: [认证]
* requestBody:
* required: true
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/LoginRequest'
* responses:
* 200:
* description: 登录成功
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/LoginResponse'
* 400:
* description: 请求参数错误
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/ApiResponse'
* 401:
* description: 用户名或密码错误
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/ApiResponse'
* 403:
* description: 用户已被禁用
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/ApiResponse'
*/
router.post('/login', async (req, res) => {
// ... 原有代码
})
/**
* @swagger
* /auth/verify:
* get:
* summary: 验证 Token
* description: 验证 JWT Token 是否有效
* tags: [认证]
* security:
* - bearerAuth: []
* responses:
* 200:
* description: Token 有效
* content:
* application/json:
* schema:
* type: object
* properties:
* code:
* type: integer
* example: 0
* msg:
* type: string
* example: Token 有效
* data:
* type: object
* properties:
* id:
* type: integer
* username:
* type: string
* email:
* type: string
* role:
* type: string
* 401:
* description: 无效的 Token
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/ApiResponse'
*/
router.get('/verify', (req, res) => {
// ... 原有代码
})
module.exports = router
2. 用户路由注释
修改 src/routes/user.js:
javascript
// src/routes/user.js
const express = require('express')
const router = express.Router()
const { authenticate, authorize } = require('../middleware/auth')
const { generateUserList, findUserById } = require('../utils/mockData')
/**
* @swagger
* /user/list:
* get:
* summary: 获取用户列表
* description: 分页获取用户列表,支持搜索和筛选
* tags: [用户管理]
* security:
* - bearerAuth: []
* parameters:
* - in: query
* name: page
* schema:
* type: integer
* default: 1
* description: 页码
* - in: query
* name: size
* schema:
* type: integer
* default: 10
* description: 每页大小
* - in: query
* name: keyword
* schema:
* type: string
* description: 关键词搜索(用户名或邮箱)
* - in: query
* name: status
* schema:
* type: integer
* enum: [0, 1]
* description: 用户状态:0-禁用,1-启用
* - in: query
* name: role
* schema:
* type: string
* enum: [admin, manager, user, developer]
* description: 用户角色
* responses:
* 200:
* description: 获取用户列表成功
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/UserListResponse'
* 400:
* description: 请求参数错误
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/ApiResponse'
* 401:
* description: 未登录或 Token 无效
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/ApiResponse'
*/
router.get('/list', authenticate, (req, res) => {
// ... 原有代码
})
/**
* @swagger
* /user/{id}:
* get:
* summary: 获取用户详情
* description: 根据用户 ID 获取详细信息
* tags: [用户管理]
* security:
* - bearerAuth: []
* parameters:
* - in: path
* name: id
* required: true
* schema:
* type: integer
* description: 用户 ID
* responses:
* 200:
* description: 获取用户详情成功
* content:
* application/json:
* schema:
* type: object
* properties:
* code:
* type: integer
* example: 0
* msg:
* type: string
* example: 获取用户详情成功
* data:
* $ref: '#/components/schemas/User'
* 401:
* description: 未登录
* 404:
* description: 用户不存在
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/ApiResponse'
*/
router.get('/:id', authenticate, (req, res) => {
// ... 原有代码
})
/**
* @swagger
* /user/info:
* get:
* summary: 获取当前用户信息
* description: 获取当前登录用户的信息
* tags: [用户管理]
* security:
* - bearerAuth: []
* responses:
* 200:
* description: 获取用户信息成功
* content:
* application/json:
* schema:
* type: object
* properties:
* code:
* type: integer
* example: 0
* msg:
* type: string
* example: 获取用户信息成功
* data:
* $ref: '#/components/schemas/User'
* 401:
* description: 未登录
*/
router.get('/info', authenticate, (req, res) => {
// ... 原有代码
})
/**
* @swagger
* /user:
* post:
* summary: 创建用户
* description: 创建新用户(需要管理员权限)
* tags: [用户管理]
* security:
* - bearerAuth: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/CreateUserRequest'
* responses:
* 200:
* description: 创建用户成功
* content:
* application/json:
* schema:
* type: object
* properties:
* code:
* type: integer
* example: 0
* msg:
* type: string
* example: 创建用户成功
* data:
* $ref: '#/components/schemas/User'
* 400:
* description: 请求参数错误
* 401:
* description: 未登录
* 403:
* description: 权限不足
*/
router.post('/', authenticate, authorize(['admin']), (req, res) => {
// ... 原有代码
})
/**
* @swagger
* /user/{id}:
* put:
* summary: 更新用户
* description: 更新用户信息(需要管理员权限)
* tags: [用户管理]
* security:
* - bearerAuth: []
* parameters:
* - in: path
* name: id
* required: true
* schema:
* type: integer
* description: 用户 ID
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* email:
* type: string
* example: newemail@example.com
* role:
* type: string
* enum: [admin, manager, user, developer]
* status:
* type: integer
* enum: [0, 1]
* description: 用户状态:0-禁用,1-启用
* responses:
* 200:
* description: 更新用户成功
* content:
* application/json:
* schema:
* type: object
* properties:
* code:
* type: integer
* example: 0
* msg:
* type: string
* example: 更新用户成功
* data:
* $ref: '#/components/schemas/User'
* 401:
* description: 未登录
* 403:
* description: 权限不足
* 404:
* description: 用户不存在
*/
router.put('/:id', authenticate, authorize(['admin']), (req, res) => {
// ... 原有代码
})
/**
* @swagger
* /user/{id}:
* delete:
* summary: 删除用户
* description: 删除指定用户(需要管理员权限)
* tags: [用户管理]
* security:
* - bearerAuth: []
* parameters:
* - in: path
* name: id
* required: true
* schema:
* type: integer
* description: 用户 ID
* responses:
* 200:
* description: 删除用户成功
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/ApiResponse'
* 401:
* description: 未登录
* 403:
* description: 权限不足
* 404:
* description: 用户不存在
*/
router.delete('/:id', authenticate, authorize(['admin']), (req, res) => {
// ... 原有代码
})
module.exports = router
🌐 第五步:访问 Swagger UI
启动服务后,在浏览器访问:
http://localhost:3000/api-docs
📖 第六步:Swagger UI 使用指南
1. 界面布局
Swagger UI 界面主要包含:
- 顶部搜索框:搜索 API 路径或描述
- 左侧导航:按 Tags 分组显示所有接口
- 右侧内容:显示选中接口的详细信息
2. 认证设置
对于需要 Token 的接口(如 /user/list),需要先设置认证:
- 点击页面右上角的 "Authorize" 按钮
- 在弹出的对话框中输入:
Bearer <你的Token> - 点击 "Authorize" 按钮
- 关闭对话框
3. 测试接口
在 Swagger UI 中可以直接测试接口:
- 展开想要测试的接口
- 点击 "Try it out" 按钮
- 填写请求参数
- 点击 "Execute" 按钮
- 查看响应结果
4. 查看响应示例
每个接口下方会显示:
- 请求示例:Curl 命令格式
- 响应示例:JSON 格式的响应数据
- 响应状态码:不同状态码的含义
🎨 第七步:自定义 Swagger UI 样式(可选)
创建 src/config/swagger.js 增强配置:
javascript
// src/config/swagger.js
const swaggerJsdoc = require('swagger-jsdoc')
// 自定义 CSS 样式
const customCss = `
.swagger-ui .topbar {
background-color: #2a3f54;
padding: 10px 0;
}
.swagger-ui .topbar .download-url-wrapper .select-label {
display: none;
}
.swagger-ui .info .title {
color: #2a3f54;
}
.swagger-ui .btn.authorize {
border-color: #2a3f54;
color: #2a3f54;
}
.swagger-ui .btn.authorize:hover {
background-color: #2a3f54;
color: #fff;
}
`
// 在 app.js 中使用
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec, {
explorer: true,
customCss: customCss,
customSiteTitle: '用户管理 API 文档',
swaggerOptions: {
persistAuthorization: true,
docExpansion: 'none', // 默认折叠所有接口:'none' | 'list' | 'full'
filter: true, // 启用过滤器
showExtensions: true,
showCommonExtensions: true,
syntaxHighlight: {
activated: true,
theme: 'monokai',
},
},
}))
📄 第八步:导出 API 文档(Markdown/PDF)
方案一:使用 swagger-to-markdown
bash
npm install swagger-to-markdown -g
bash
# 导出为 Markdown
swagger-to-markdown http://localhost:3000/api-docs.json > API_DOCS.md
方案二:使用 Swagger Editor 导出
- 访问 Swagger Editor
- 导入
http://localhost:3000/api-docs.json - 点击 "Generate Client" → 选择格式(HTML/PDF 等)
🔧 第九步:常见问题解决
问题1:Swagger 页面空白
原因:可能是 CORS 或路由配置问题。
解决:
javascript
// 确保 CORS 配置正确
app.use(cors())
// 确保 Swagger UI 路由在其他路由之前
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec))
问题2:JSDoc 注释没有被解析
原因 :apis 路径配置不正确。
解决:
javascript
// 在 swagger.js 中检查 apis 配置
apis: ['./src/routes/*.js'], // 确保路径正确
问题3:Swagger 中显示不了中文
解决:
javascript
// 在 package.json 中添加
{
"scripts": {
"dev": "nodemon --exec \"node -r ./src/config/swagger.js src/app.js\""
}
}
📊 第十步:完整效果预览
启动服务后,访问 http://localhost:3000/api-docs,你将看到:
- API 分组:认证、用户管理
- 接口列表:所有接口清晰展示
- 参数说明:每个参数的详细说明
- 在线测试:直接在界面上测试接口
- 响应示例:查看预期的响应格式
- 认证集成:Bearer Token 认证
🎯 总结
使用 Swagger 的好处:
- 可视化文档:自动生成美观的 API 文档
- 在线测试:直接测试接口,无需 Postman
- 标准化:遵循 OpenAPI 规范
- 交互式:支持参数填写和响应查看
- 易于维护:代码即文档,保持同步
- 团队协作:方便前后端联调
现在你的后端服务不仅有完整的接口功能,还有专业的 API 文档,便于前端开发和团队协作!