# Bug Fix: Required Fields 判定錯誤 ## 🐛 問題描述 生成的 OpenAPI/Swagger 文檔中,所有結構體字段都被錯誤地標記為 `required`,即使這些字段: - 是**指針類型** (`*string`, `*int`, `*int64`) - 在 JSON 標籤中包含 **`omitempty`** - 在 validate 標籤中包含 **`omitempty`** ### 問題示例 ```go type CreateUserInfoReq { UID string `json:"uid" validate:"required"` // 必填 Avatar *string `json:"avatar,omitempty"` // 應該可選 NickName *string `json:"nick_name,omitempty"` // 應該可選 Language string `json:"language" validate:"required"` // 必填 } ``` **修復前生成的 required 列表:** ```json "required": ["uid", "avatar", "nick_name", "language"] ``` **修復後正確的 required 列表:** ```json "required": ["uid", "language"] ``` ## 🔍 根本原因 `internal/swagger/swagger.go` 中的 `isRequired()` 函數只檢查 JSON 標籤中的 `optional` 標記,但沒有檢查: 1. 字段類型是否為指針(指針類型在 Go 中表示可選) 2. JSON 標籤是否包含 `omitempty` ## ✅ 修復方案 ### 修改的文件 - `internal/swagger/swagger.go` ### 修改內容 #### 1. 修改 `rangeMemberAndDo` 函數簽名 ```go // 修改前 required := isRequired(ctx, tags) // 修改後 required := isRequired(ctx, tags, field) ``` #### 2. 修改 `isRequired` 函數 ```go // 修改前 func isRequired(ctx Context, tags *apiSpec.Tags) bool { tag, err := tags.Get(tagJson) if err == nil { return !isOptional(ctx, tag.Options) } // ... return false } // 修改後 func isRequired(ctx Context, tags *apiSpec.Tags, member apiSpec.Member) bool { // Check if the field type is a pointer - pointer types are optional if _, isPointer := member.Type.(apiSpec.PointerType); isPointer { return false } tag, err := tags.Get(tagJson) if err == nil { return !isOptional(ctx, tag.Options) } // ... return false } ``` #### 3. 修改 `isOptional` 函數 ```go // 修改前 func isOptional(_ Context, options []string) bool { for _, option := range options { if option == optionalFlag { return true } } return false } // 修改後 func isOptional(_ Context, options []string) bool { for _, option := range options { if option == optionalFlag || option == "omitempty" { return true } } return false } ``` ## 📊 驗證結果 使用 `example/api/gateway.api` 進行測試: | 結構體 | 修復前 | 修復後 | 狀態 | |--------|--------|--------|------| | CreateUserInfoReq | 13 個必填 | 5 個必填 | ✅ | | UpdateUserInfoReq | 11 個必填 | 1 個必填 | ✅ | | ListUserInfoReq | 6 個必填 | 2 個必填 | ✅ | | GetUserInfoReq | 2 個必填 | 0 個必填 | ✅ | | BindingUserReq | 3 個必填 | 3 個必填 | ✅ | ### CreateUserInfoReq 詳細對比 **必填字段(非指針類型):** - `uid` (string) - `alarm_type` (int) - `status` (int) - `language` (string) - `currency` (string) **可選字段(指針類型):** - `avatar` (*string) - `nick_name` (*string) - `full_name` (*string) - `gender` (*int64) - `birthdate` (*int64) - `phone_number` (*string) - `email` (*string) - `address` (*string) ## 🚀 影響範圍 此修復影響所有使用 go-doc 生成的 OpenAPI/Swagger 文檔: - ✅ Swagger 2.0 格式 - ✅ OpenAPI 3.0 格式 - ✅ JSON 輸出 - ✅ YAML 輸出 ## 📝 開發者注意事項 在 Go 語言和 API 設計中,以下三種方式都表示字段為可選: 1. **指針類型** - `*string`, `*int`, `*int64` 等 2. **JSON 標籤的 `omitempty`** - `json:"field,omitempty"` 3. **Validate 標籤的 `omitempty`** - `validate:"omitempty,..."` 修復後的 go-doc 工具會正確識別這些模式。 ## 🔗 相關文件 - 修改文件:`internal/swagger/swagger.go` - 測試文件:`example/api/gateway.api` - 生成文件:`example/test_output/gateway.json` - 驗證腳本:可運行 `make gen-gateway` 重新生成並驗證 ## ✅ 測試通過 ```bash # 重新構建 make build # 生成 gateway API 文檔 ./bin/go-doc --api example/api/gateway.api \ --dir example/test_output \ --filename gateway \ --spec-version openapi3.0 # 所有結構體的 required 字段現在都正確了! ``` --- **修復日期:** 2025-10-01 **修復版本:** 1.2.1 **問題類型:** Bug Fix **嚴重程度:** High (影響 API 文檔準確性)