iT邦幫忙

2025 iThome 鐵人賽

DAY 28
0
Modern Web

現在就學Node.js系列 第 28

API 文件自動化 — 用 Swagger + JSDoc 打造開發者友善介面 -Day28

  • 分享至 

  • xImage
  •  

在後端開發中,最麻煩的不是寫 API,而是沒人知道怎麼用 API。

後端:「規格與使用說明都放在 Notion。」

前端:「為什麼照規格打過去卻沒反應?怎麼回來的欄位又多一個?」

結果大家都在猜參數、對格式、測半天。

文件不同步、溝通成本高,是每個開發團隊的困擾。

為什麼要用 Swagger?

Swagger 正是解決這個痛點的利器。

它能讓你的 API 自動長出文件、即時更新,

而且直接在瀏覽器中就能進行測試。

不再需要手動更新 Postman,不怕文件落後實作。

只要在程式碼上加上註解,Swagger 就能:

  • 自動生成文件頁面
  • 即時同步 API 狀態
  • 支援 JWT 登入測試

Swagger 讓你的 API 有「使用說明書」,

讓開發、測試、協作都能一氣呵成,溝通更順暢。

Step 1:安裝 Swagger 套件

在你的專案中執行:

npm install swagger-jsdoc swagger-ui-express

Step 2:建立 Swagger 設定檔

新增一個 swagger.js(放在根目錄或 config/ 資料夾皆可):

// swagger.js
import swaggerJSDoc from 'swagger-jsdoc'
import swaggerUi from 'swagger-ui-express'

const options = {
  definition: {
    openapi: '3.0.0',
    info: {
      title: 'RBAC Blog API 文件',
      version: '1.0.0',
      description: `
這是使用 **Swagger + JSDoc** 自動生成的 API 文件。
提供完整的登入、註冊、文章 CRUD 與權限控管範例。
      `,
    },
    servers: [{ url: 'http://localhost:3000' }],
    components: {
      securitySchemes: {
        BearerAuth: {
          type: 'http',
          scheme: 'bearer',
          bearerFormat: 'JWT',
        },
      },
    },
  },
  apis: ['./routes/*.js'], // 掃描所有路由檔案中的 JSDoc 註解
}

export const swaggerSpec = swaggerJSDoc(options)

export const swaggerDocs = app => {
  app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec))
  console.log('📘 Swagger 文件啟動:http://localhost:3000/api-docs')
}

Step 3:在主伺服器掛上 Swagger UI

server.jsapp.js 匯入設定:

// app.js
import express from 'express'
import mongoose from 'mongoose'
import authRoutes from './routes/auth.js'
import postRoutes from './routes/post.js'
import { swaggerDocs } from './swagger.js'

const app = express()
app.use(express.json())

app.use('/auth', authRoutes)
app.use('/posts', postRoutes)

// 啟用 Swagger 文件
swaggerDocs(app)

mongoose.connect(process.env.MONGO_URL)
app.listen(3000, () => console.log('🚀 Server running on http://localhost:3000'))

Step 4:為 API 加上 JSDoc 註解

它會根據你在路由上方的註解,自動產生 OpenAPI 文件

以下示範在 auth.jspost.js 加上註解

📂 routes/auth.js

/**
 * @swagger
 * tags:
 *   name: Auth
 *   description: 使用者認證相關 API
 */

/**
 * @swagger
 * /auth/register:
 *   post:
 *     summary: 使用者註冊
 *     tags: [Auth]
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *             required:
 *               - email
 *               - password
 *             properties:
 *               email:
 *                 type: string
 *                 example: test@test.com
 *               password:
 *                 type: string
 *                 example: 123456
 *               role:
 *                 type: string
 *                 enum: [user, editor, admin]
 *     responses:
 *       200:
 *         description: 註冊成功
 */

/**
 * @swagger
 * /auth/login:
 *   post:
 *     summary: 使用者登入
 *     tags: [Auth]
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *             properties:
 *               email:
 *                 type: string
 *                 example: test@test.com
 *               password:
 *                 type: string
 *                 example: 123456
 *     responses:
 *       200:
 *         description: 登入成功
 *       401:
 *         description: 帳號或密碼錯誤
 */

📂 routes/post.js

/**
 * @swagger
 * tags:
 *   name: Posts
 *   description: 文章管理相關 API
 */

/**
 * @swagger
 * /posts:
 *   get:
 *     summary: 取得所有文章
 *     security:
 *       - BearerAuth: []
 *     tags: [Posts]
 *     responses:
 *       200:
 *         description: 成功取得文章列表
 */

/**
 * @swagger
 * /posts:
 *   post:
 *     summary: 新增文章
 *     tags: [Posts]
 *     security:
 *       - BearerAuth: []
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *             properties:
 *               title:
 *                 type: string
 *                 example: Node.js RBAC 入門
 *               content:
 *                 type: string
 *                 example: 這是一篇教你如何實作 RBAC 的文章。
 *     responses:
 *       201:
 *         description: 文章建立成功
 *       403:
 *         description: 權限不足
 */

/**
 * @swagger
 * /posts/{id}:
 *   put:
 *     summary: 編輯文章
 *     tags: [Posts]
 *     security:
 *       - BearerAuth: []
 *     parameters:
 *       - in: path
 *         name: id
 *         required: true
 *         schema:
 *           type: string
 *         description: 文章 ID
 *     responses:
 *       200:
 *         description: 文章已更新
 *       403:
 *         description: 無權限編輯
 */

/**
 * @swagger
 * /posts/{id}:
 *   delete:
 *     summary: 刪除文章(限 admin)
 *     tags: [Posts]
 *     security:
 *       - BearerAuth: []
 *     parameters:
 *       - in: path
 *         name: id
 *         required: true
 *         schema:
 *           type: string
 *     responses:
 *       200:
 *         description: 文章已刪除
 *       403:
 *         description: 無權限刪除
 */

Step 5:設定 JWT 安全機制(BearerAuth)

由於我們的 API 使用 JWT 驗證,

需要在 Swagger 設定中加上 securitySchemes

components: {
  securitySchemes: {
    BearerAuth: {
      type: 'http',
      scheme: 'bearer',
      bearerFormat: 'JWT',
    },
  },
}

這樣 Swagger UI 右上角會出現「Authorize 🔒」按鈕,

貼上登入後取得的 Token,就能直接測試受保護的 API。

Step 6:啟動伺服器,查看文件!

啟動開發伺服器:

npm run dev

打開瀏覽器:

http://localhost:3000/api-docs

你會看到自動生成的互動式 API 文件,

可直接輸入參數、發送請求、查看回應 — 全部在瀏覽器搞定!

小技巧

  • 文件會隨著你修改註解而即時更新
  • 可用 /v1, /v2 版本路徑管理不同 API 版本

小結

今天我們完成了 API 文件自動化 的最後一哩路

功能 工具 說明
自動生成文件 swagger-jsdoc 從 JSDoc 註解轉為 OpenAPI JSON
文件展示介面 swagger-ui-express 可互動操作 API
權限整合 BearerAuth (JWT) 模擬登入驗證

讓你的後端不只是「能跑」,

而是「有文件、有測試、有溝通」的系統。

延伸閱讀:OpenAPI 3.0 完整指南

如果你想更深入了解 OpenAPI 3.0 的結構與規範

例如:

  • pathscomponentsschemas 如何組成完整規格文件
  • security 與多層驗證機制設計
  • 如何轉出成 YAML / JSON 並部署 API 文件伺服器

可參考這篇延伸教學 👉

OpenAPI 3.0 完整指南:打造自己的 API 文件 | by 黃禎平 | Medium


上一篇
RBAC 角色權限控管(下)— React + Chakra UI 權限控制 - Day27
下一篇
Nginx 反向代理入門 — 前後端網關整合 - Day29
系列文
現在就學Node.js29
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言