## Context 当前项目使用 `github.com/swaggest/openapi-go/openapi3` 库生成 OpenAPI 3.0.3 规范文档。路由注册通过 `RouteSpec` 结构体传递元数据,但目前只支持 `Summary` 字段作为接口的简短描述。 OpenAPI 规范的 Operation 对象包含两个描述字段: - `summary`: 简短摘要(通常一行) - `description`: 详细说明,**支持 CommonMark Markdown 语法** swaggest 库的 `openapi3.Operation` 结构体已包含 `Description *string` 字段,只需在代码中设置即可。 ## Goals / Non-Goals **Goals:** - 在 `RouteSpec` 中新增 `Description` 字段 - 支持在接口文档中添加 Markdown 格式的详细说明 - 保持向后兼容,Description 为可选字段 - 更新 API 文档规范 **Non-Goals:** - 不修改 DTO 字段的 description 标签处理逻辑 - 不修改现有路由注册代码(新字段可选) - 不扩展其他 OpenAPI 字段(如 externalDocs、deprecated 等) ## Decisions ### 决策 1: Description 字段类型 **选择**: 使用 `string` 类型 **原因**: - 与 `Summary` 字段保持一致 - 空字符串表示无描述,语义清晰 - 避免指针类型带来的 nil 检查复杂度 **备选方案**: - `*string` 指针类型 - 增加使用复杂度,无实际收益 ### 决策 2: 函数签名变更策略 **选择**: 不修改 `AddOperation` 函数签名,通过 `RouteSpec.Description` 传递 **原因**: - 保持 API 稳定性 - `Register` 函数已封装了 `RouteSpec`,只需从中提取 Description - 避免破坏性变更 **备选方案**: - 修改 `AddOperation` 增加 description 参数 - 需要修改所有调用点,不必要 ### 决策 3: 空值处理 **选择**: 空字符串时不设置 OpenAPI 的 description 字段 **原因**: - 生成更简洁的 YAML - 与 swaggest 库的 omitempty 行为一致 - 保持现有生成文件格式不变 ## Risks / Trade-offs **[风险] Markdown 语法在不同工具中渲染差异** → 缓解: 建议使用 CommonMark 基础语法(标题、列表、表格、代码块),避免扩展语法 **[风险] 过长的 Description 影响文档可读性** → 缓解: 在规范文档中建议控制长度,复杂说明可使用折叠或链接到外部文档 **[权衡] 不修改函数签名 vs 显式参数** → 选择封装在 RouteSpec 中,牺牲一定的显式性换取稳定性 ## 实现方案 ### 文件变更清单 1. **`internal/routes/registry.go`** - RouteSpec 新增 Description 字段 2. **`pkg/openapi/generator.go`** - AddOperation: 设置 op.Description - AddMultipartOperation: 设置 op.Description 3. **`docs/api-documentation-guide.md`** - 新增 Description 字段使用说明 - 补充 Markdown 语法示例 ### 代码变更示例 ```go // internal/routes/registry.go type RouteSpec struct { Summary string // 简短摘要 Description string // 详细说明,支持 Markdown Input interface{} Output interface{} Tags []string Auth bool FileUploads []FileUploadField } ``` ```go // pkg/openapi/generator.go - AddOperation func (g *Generator) AddOperation(...) { op := openapi3.Operation{ Summary: &summary, Tags: tags, } // 新增: 设置 Description if description != "" { op.Description = &description } // ... } ```