Go to file
王性驊 7c309f3508 feat: add doc generate 2025-10-01 17:44:41 +08:00
cmd/go-doc feat: add doc generate 2025-09-30 17:33:29 +08:00
example feat: add doc generate 2025-10-01 17:44:41 +08:00
internal feat: add doc generate 2025-10-01 17:44:41 +08:00
.gitignore feat: init swagger project 2025-09-30 16:52:30 +08:00
BUGFIX_REQUIRED_FIELDS.md feat: add doc generate 2025-10-01 17:44:41 +08:00
LICENSE feat: init swagger project 2025-09-30 16:16:44 +08:00
Makefile feat: add doc generate 2025-10-01 17:44:41 +08:00
README.md feat: add doc generate 2025-09-30 17:33:29 +08:00
cursor.md feat: init swagger project 2025-09-30 16:16:44 +08:00
go.mod feat: init swagger project 2025-09-30 16:52:30 +08:00
go.sum feat: init swagger project 2025-09-30 16:52:30 +08:00
test_all_formats.sh feat: init swagger project 2025-09-30 16:52:30 +08:00
test_respdoc.sh feat: add doc generate 2025-09-30 17:33:29 +08:00

README.md

go-doc

Go Version License Version

go-doc 是一個獨立的命令行工具,專門用於將 go-zero .api 文件轉換為 OpenAPI 規範文檔。

原本是 go-zero 專案的一部分,現在已獨立出來,成為一個易於使用的工具,支援生成 Swagger 2.0OpenAPI 3.0 兩種格式。


📑 目錄


特性

  • 🚀 獨立二進制 - 無需依賴 go-zero 運行時
  • 📝 雙規格支援 - 生成 Swagger 2.0OpenAPI 3.0 格式
  • 🎯 豐富的類型支援 - 處理結構體、陣列、映射、指針和嵌套類型
  • 🏷️ 基於標籤的配置 - 支援 jsonformpathheader 標籤
  • 📊 進階驗證 - 範圍、枚舉、預設值、範例值
  • 🔐 安全定義 - 自定義身份驗證配置
  • 📦 多種輸出格式 - JSON 或 YAML 輸出
  • 🎨 定義引用 - 可選使用 definitions/schemas 使輸出更簡潔
  • 🔄 自動轉換 - Swagger 2.0 到 OpenAPI 3.0 的無縫轉換
  • 🆕 多狀態碼回應 - 使用 @respdoc 定義多個 HTTP 狀態碼
  • 🆕 業務錯誤碼映射 - 將業務錯誤碼映射到不同的錯誤類型OpenAPI 3.0 使用 oneOf

📦 安裝

從源碼編譯

git clone <your-repo>
cd go-doc
make build

編譯完成後,執行檔位於 bin/go-doc

使用 Go Install

go install github.com/danielchan-25/go-doc/cmd/go-doc@latest

🚀 快速開始

基本使用

# 生成 Swagger 2.0(預設)
go-doc -a example/example.api -d output

# 生成 OpenAPI 3.0(推薦)
go-doc -a example/example.api -d output -s openapi3.0

# 生成 YAML 格式
go-doc -a example/example.api -d output -y

# 生成 OpenAPI 3.0 YAML
go-doc -a example/example.api -d output -s openapi3.0 -y

# 自訂檔名
go-doc -a example/example.api -d output -f my-api

命令行選項

Flags:
  -a, --api string            API 文件路徑(必要)
  -d, --dir string            輸出目錄(必要)
  -f, --filename string       輸出檔名(不含副檔名)
  -h, --help                  顯示說明
  -s, --spec-version string   OpenAPI 規格版本swagger2.0 或 openapi3.0預設swagger2.0
  -v, --version               顯示版本
  -y, --yaml                  生成 YAML 格式預設JSON

使用 Makefile

# 編譯
make build

# 生成範例
make example

# 清理
make clean

# 運行測試
make test

# 查看所有命令
make help

📖 API 文件格式

基本結構

syntax = "v1"

info (
    title:       "My API"
    description: "API documentation"
    version:     "v1.0.0"
    host:        "api.example.com"
    basePath:    "/v1"
)

type (
    UserRequest {
        Id   int    `json:"id,range=[1:10000]"`
        Name string `json:"name"`
    }
    UserResponse {
        Id   int    `json:"id"`
        Name string `json:"name"`
    }
)

@server (
    tags: "user"
)
service MyAPI {
    @handler getUser
    get /user/:id (UserRequest) returns (UserResponse)
}

支援的 Info 屬性

  • title - API 標題
  • description - API 描述
  • version - API 版本
  • host - API 主機(如 "api.example.com"
  • basePath - 基礎路徑(如 "/v1"
  • schemes - 協議(如 "http,https"
  • consumes - 請求內容類型
  • produces - 回應內容類型
  • contactName, contactURL, contactEmail - 聯絡資訊
  • licenseName, licenseURL - 授權資訊
  • useDefinitions - 使用 Swagger definitionstrue/false
  • wrapCodeMsg - 將回應包裝在 {code, msg, data} 結構中
  • securityDefinitionsFromJson - JSON 格式的安全定義

標籤選項

JSON 標籤

type Example {
    // 範圍驗證
    Age int `json:"age,range=[1:150]"`
    
    // 預設值
    Status string `json:"status,default=active"`
    
    // 範例值
    Email string `json:"email,example=user@example.com"`
    
    // 枚舉值
    Role string `json:"role,options=admin|user|guest"`
    
    // 可選欄位
    Phone string `json:"phone,optional"`
}

Form 標籤

type QueryRequest {
    Keyword string `form:"keyword"`
    Page    int    `form:"page,default=1"`
    Size    int    `form:"size,range=[1:100]"`
}

Path 標籤

type PathRequest {
    UserId int `path:"userId,range=[1:999999]"`
}

Header 標籤

type HeaderRequest {
    Token string `header:"Authorization"`
}

🆕 @respdoc 多狀態碼回應

概述

@respdoc 註解允許您為單個 API 端點定義多個 HTTP 狀態碼的回應,並支援為同一狀態碼定義多種業務錯誤格式。

重要特性:

  • 支援多個 HTTP 狀態碼200, 201, 400, 401, 404, 500 等)
  • 支援業務錯誤碼映射(如 300101, 300102 等)
  • OpenAPI 3.0 使用 oneOf 表示多種錯誤格式
  • Swagger 2.0 在描述中列出所有可能的錯誤

基本語法

單一回應類型

service MyAPI {
    @doc (
        description: "用戶查詢接口"
    )
    /*
        @respdoc-200 (UserResponse) // 成功
        @respdoc-400 (ErrorResponse) // 錯誤請求
        @respdoc-401 (UnauthorizedError) // 未授權
        @respdoc-500 (ServerError) // 服務器錯誤
    */
    @handler getUser
    get /user/:id (UserRequest) returns (UserResponse)
}

多業務錯誤碼(重點功能)

service MyAPI {
    @doc (
        description: "創建訂單"
    )
    /*
        @respdoc-201 (OrderResponse) // 創建成功
        @respdoc-400 (
            300101: (ValidationError) 參數驗證失敗
            300102: (InsufficientStockError) 庫存不足
            300103: (InvalidPaymentError) 支付方式無效
        ) // 客戶端錯誤
        @respdoc-401 (UnauthorizedError) // 未授權
        @respdoc-500 (ServerError) // 服務器錯誤
    */
    @handler createOrder
    post /order (OrderRequest) returns (OrderResponse)
}

完整範例

syntax = "v1"

info (
    title: "訂單 API"
    description: "訂單管理系統"
    version: "v1"
    host: "api.example.com"
    basePath: "/v1"
    useDefinitions: true
)

type (
    CreateOrderReq {
        ProductID string `json:"product_id"`
        Quantity  int    `json:"quantity"`
        PaymentMethod string `json:"payment_method"`
    }
    
    OrderResponse {
        OrderID   string `json:"order_id"`
        Status    string `json:"status"`
        Total     float64 `json:"total"`
    }
    
    ValidationError {
        Code    string   `json:"code"`
        Message string   `json:"message"`
        Fields  []string `json:"fields"`
    }
    
    InsufficientStockError {
        Code      string `json:"code"`
        Message   string `json:"message"`
        ProductID string `json:"product_id"`
        Required  int    `json:"required"`
        Available int    `json:"available"`
    }
    
    InvalidPaymentError {
        Code    string `json:"code"`
        Message string `json:"message"`
        Method  string `json:"method"`
    }
    
    UnauthorizedError {
        Code    string `json:"code"`
        Message string `json:"message"`
        Reason  string `json:"reason"`
    }
    
    ServerError {
        Code    string `json:"code"`
        Message string `json:"message"`
        TraceID string `json:"trace_id"`
    }
)

@server (
    tags: "order"
)
service OrderAPI {
    @doc (
        description: "創建訂單"
    )
    /*
        @respdoc-201 (OrderResponse) // 創建成功
        @respdoc-400 (
            300101: (ValidationError) 參數驗證失敗
            300102: (InsufficientStockError) 庫存不足
            300103: (InvalidPaymentError) 支付方式無效
        ) // 客戶端錯誤
        @respdoc-401 (UnauthorizedError) // 未授權
        @respdoc-500 (ServerError) // 服務器錯誤
    */
    @handler createOrder
    post /order (CreateOrderReq) returns (OrderResponse)
}

生成結果對比

Swagger 2.0 輸出

{
  "paths": {
    "/v1/order": {
      "post": {
        "responses": {
          "201": {
            "description": "// 創建成功",
            "schema": {
              "$ref": "#/definitions/OrderResponse"
            }
          },
          "400": {
            "description": "客戶端錯誤\n\nPossible errors:\n300101: ValidationError - 參數驗證失敗\n300102: InsufficientStockError - 庫存不足\n300103: InvalidPaymentError - 支付方式無效",
            "schema": {
              "$ref": "#/definitions/ValidationError"
            }
          }
        }
      }
    }
  }
}

OpenAPI 3.0 輸出(使用 oneOf

{
  "paths": {
    "/v1/order": {
      "post": {
        "responses": {
          "201": {
            "description": "// 創建成功",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderResponse"
                }
              }
            }
          },
          "400": {
            "description": "客戶端錯誤",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ValidationError"
                    },
                    {
                      "$ref": "#/components/schemas/InsufficientStockError"
                    },
                    {
                      "$ref": "#/components/schemas/InvalidPaymentError"
                    }
                  ]
                }
              }
            }
          }
        }
      }
    }
  }
}

優勢: OpenAPI 3.0 使用 oneOf 精確表示多種可能的錯誤類型!


🔧 進階功能

安全定義

info (
    securityDefinitionsFromJson: `{
        "apiKey": {
            "type": "apiKey",
            "name": "x-api-key",
            "in": "header",
            "description": "API Key Authentication"
        }
    }`
)

@server (
    authType: apiKey
)
service MyAPI {
    // 此處的路由將使用 apiKey 身份驗證
}

Code-Msg 包裝

info (
    wrapCodeMsg: true
    bizCodeEnumDescription: "1001-User not found<br>1002-Permission denied"
)

回應將被包裝為:

{
    "code": 0,
    "msg": "ok",
    "data": { /* your actual response */ }
}

🎯 OpenAPI 3.0 vs Swagger 2.0

規格版本

Swagger 2.0(預設)

go-doc -a example/example.api -d output
# 或明確指定
go-doc -a example/example.api -d output -s swagger2.0

OpenAPI 3.0(推薦)

go-doc -a example/example.api -d output -s openapi3.0

主要差異

特性 Swagger 2.0 OpenAPI 3.0
版本聲明 swagger: "2.0" openapi: "3.0.3"
服務器 host, basePath, schemes servers 陣列
Schema 定義 definitions components/schemas
安全定義 securityDefinitions components/securitySchemes
請求體 parameters[in=body] requestBody
多類型回應 不支援 oneOf/anyOf/allOf

範例對比

Swagger 2.0:

{
  "swagger": "2.0",
  "host": "example.com",
  "basePath": "/v1",
  "definitions": {
    "User": {...}
  },
  "securityDefinitions": {
    "apiKey": {...}
  }
}

OpenAPI 3.0:

{
  "openapi": "3.0.3",
  "servers": [
    {"url": "http://example.com/v1"},
    {"url": "https://example.com/v1"}
  ],
  "components": {
    "schemas": {
      "User": {...}
    },
    "securitySchemes": {
      "apiKey": {...}
    }
  }
}

💡 使用範例

場景 1RESTful CRUD

/*
    @respdoc-200 (UserResponse) // 獲取成功
    @respdoc-404 (NotFoundError) // 用戶不存在
    @respdoc-401 (UnauthorizedError) // 未授權
*/
@handler getUser
get /user/:id (UserIdReq) returns (UserResponse)

/*
    @respdoc-201 (UserResponse) // 創建成功
    @respdoc-400 (ValidationError) // 參數錯誤
    @respdoc-409 (ConflictError) // 用戶已存在
*/
@handler createUser
post /user (CreateUserReq) returns (UserResponse)

/*
    @respdoc-200 (UserResponse) // 更新成功
    @respdoc-400 (ValidationError) // 參數錯誤
    @respdoc-404 (NotFoundError) // 用戶不存在
*/
@handler updateUser
put /user/:id (UpdateUserReq) returns (UserResponse)

/*
    @respdoc-204 // 刪除成功
    @respdoc-404 (NotFoundError) // 用戶不存在
*/
@handler deleteUser
delete /user/:id (UserIdReq)

場景 2複雜業務流程

/*
    @respdoc-200 (PaymentResponse) // 支付成功
    @respdoc-400 (
        400001: (InsufficientBalanceError) 餘額不足
        400002: (InvalidCardError) 無效的卡號
        400003: (ExpiredCardError) 卡已過期
        400004: (DailyLimitError) 超過每日限額
    ) // 支付失敗
    @respdoc-401 (UnauthorizedError) // 未授權
    @respdoc-422 (ProcessingError) // 處理中請勿重複提交
*/
@handler processPayment
post /payment (PaymentRequest) returns (PaymentResponse)

場景 3狀態機轉換

/*
    @respdoc-200 (OrderResponse) // 狀態更新成功
    @respdoc-400 (
        400001: (InvalidStateError) 無效的狀態轉換
        400002: (OrderCancelledError) 訂單已取消
        400003: (OrderCompletedError) 訂單已完成
    ) // 狀態轉換失敗
*/
@handler updateOrderStatus
put /order/:id/status (UpdateStatusReq) returns (OrderResponse)

🧪 測試

測試所有格式

# 測試 Swagger 2.0 和 OpenAPI 3.0
./test_all_formats.sh

# 測試 @respdoc 功能
./test_respdoc.sh

手動測試

# 生成並檢查
go-doc -a example/example_respdoc.api -d output -s openapi3.0

# 查看生成的文檔
cat output/example_respdoc.json | jq '.paths."/v1/order".post.responses'

📚 專案結構

go-doc/
├── cmd/
│   └── go-doc/              # 主程式入口
│       └── main.go
├── internal/
│   ├── swagger/             # 核心邏輯
│   │   ├── respdoc.go       # @respdoc 解析
│   │   ├── response.go      # 回應生成
│   │   ├── openapi3.go      # OpenAPI 3.0 轉換
│   │   ├── swagger.go       # Swagger 2.0 生成
│   │   ├── path.go          # 路徑處理
│   │   ├── parameter.go     # 參數處理
│   │   ├── definition.go    # 定義處理
│   │   └── ...
│   └── util/                # 工具函數
│       ├── util.go
│       ├── stringx.go
│       └── pathx.go
├── example/
│   ├── example.api          # 範例 API
│   ├── example_cn.api       # 中文範例
│   ├── example_respdoc.api  # @respdoc 範例
│   └── test_output/         # 生成的文檔
├── bin/                     # 編譯後的執行檔
├── go.mod
├── go.sum
├── Makefile
├── README.md
├── LICENSE
├── CHANGELOG.md
├── test_all_formats.sh      # 測試腳本
└── test_respdoc.sh          # @respdoc 測試

🔄 從 go-zero 遷移

主要變更

1. 模組獨立

之前go-zero plugin:

// 屬於 go-zero 內部工具
package swagger // in tools/goctl/api/plugin/swagger/

現在standalone:

module go-doc

package swagger // in internal/swagger/

2. 依賴簡化

依賴 替換為 原因
go-zero/tools/goctl/internal/version 自定義版本 內部包不可訪問
go-zero/tools/goctl/util go-doc/internal/util 自包含工具
go-zero/tools/goctl/util/stringx go-doc/internal/util 自定義字串處理
go-zero/tools/goctl/util/pathx go-doc/internal/util 自定義路徑處理
google.golang.org/grpc/metadata 原生 map 處理 移除外部依賴

3. 保留的依賴

  • github.com/go-openapi/spec - Swagger 2.0
  • github.com/getkin/kin-openapi - OpenAPI 3.0
  • github.com/spf13/cobra - CLI 框架
  • github.com/zeromicro/go-zero/tools/goctl/api/spec - API 解析
  • gopkg.in/yaml.v2 - YAML 支援

遷移步驟

  1. 安裝 go-doc

    go build -o bin/go-doc ./cmd/go-doc
    
  2. 替換命令

    之前:

    goctl api plugin -plugin goctl-swagger="swagger -filename api.json" -api user.api -dir .
    

    現在:

    go-doc -a user.api -d . -f api
    
  3. 新功能

    使用 OpenAPI 3.0

    go-doc -a user.api -d . -f api -s openapi3.0
    

    使用 @respdoc

    /*
        @respdoc-200 (Response) // 成功
        @respdoc-400 (Error) // 錯誤
    */
    

📝 版本記錄

[1.2.0] - 2025-09-30

新增

  • @respdoc 註解支援 - 為單個端點定義多個 HTTP 狀態碼
  • 業務錯誤碼映射 - 將不同的業務錯誤碼映射到特定錯誤類型
  • OpenAPI 3.0 oneOf 支援 - 使用 oneOf 表示多種可能的錯誤回應
  • 測試腳本 test_respdoc.sh
  • 支援解析 HandlerDoc 註釋(在 @doc() 外)

增強

  • 回應生成現在支援多個狀態碼200, 201, 400, 401, 404, 500 等)
  • OpenAPI 3.0 生成器為業務錯誤碼創建 oneOf schema
  • Swagger 2.0 在描述中列出所有可能的錯誤

[1.1.0] - 2025-09-30

新增

  • OpenAPI 3.0 支援 - 生成 Swagger 2.0 和 OpenAPI 3.0 規格
  • 新增 --spec-version (-s) 標誌
  • 自動從 Swagger 2.0 轉換到 OpenAPI 3.0
  • 整合 github.com/getkin/kin-openapi 函式庫

[1.0.0] - 2025-09-30

新增

  • 初始發布為獨立工具
  • 從 go-zero 專案提取並獨立
  • 支援將 go-zero .api 文件轉換為 Swagger 2.0 規格
  • JSON 和 YAML 輸出格式
  • 使用 cobra 的命令行介面

常見問題

Q: 應該使用哪個版本?

A:

  • Swagger 2.0: 如果需要與舊工具或系統相容
  • OpenAPI 3.0: 推薦使用,功能更強大且為現代標準

Q: 為什麼 OpenAPI 3.0 使用 oneOf

A: oneOf 是 OpenAPI 3.0 的標準方式來表示"多選一"的 schema。這讓 API 文檔更精確,工具(如 Swagger UI、代碼生成器可以正確理解和處理多種可能的回應類型。

Q: Swagger 2.0 為什麼不支援 oneOf

A: Swagger 2.0 規範不包含 oneOf 關鍵字。我們在描述中列出所有可能的錯誤,並使用第一個類型作為 schema 示例。

Q: 可以同時生成兩種格式嗎?

A: 可以!執行兩次命令即可:

go-doc -a api.api -d out -f api-v2
go-doc -a api.api -d out -f api-v3 -s openapi3.0

Q: 可以不定義業務錯誤碼嗎?

A: 可以!如果只有一種錯誤類型,直接使用單一回應格式:

@respdoc-400 (ValidationError) // 參數錯誤

Q: 如何驗證生成的文檔?

A: 可以使用以下工具:

  • Swagger Editor: https://editor.swagger.io/
  • Swagger UI: 本地運行或線上版本
  • OpenAPI Generator: 生成客戶端/伺服器代碼來驗證

🤝 貢獻

歡迎貢獻!請隨時提交 Pull Request。

開發

# 克隆專案
git clone <your-repo>
cd go-doc

# 安裝依賴
go mod download

# 運行測試
make test

# 編譯
make build

# 運行範例
make example

📄 授權

MIT License

Copyright (c) 2025 Daniel Chan

本專案最初是 go-zero 專案 swagger 生成插件的一部分。我們感謝 go-zero 團隊的出色工作。


🎉 總結

go-doc v1.2.0 提供了強大的 API 文檔生成功能:

雙規格支援 - Swagger 2.0 和 OpenAPI 3.0
多狀態碼回應 - 使用 @respdoc 定義完整的 HTTP 回應
業務錯誤碼映射 - 支援複雜的錯誤場景
OpenAPI 3.0 oneOf - 專業的多類型回應表示
完整測試 - 自動化測試腳本
詳細文檔 - 完整的使用指南

開始使用:

go-doc -a your-api.api -d docs -s openapi3.0

查看範例:

  • 基本範例:example/example.api
  • @respdoc 範例:example/example_respdoc.api
  • 測試腳本:./test_respdoc.sh

🌟 如果這個專案對您有幫助,請給個 Star