# Code First API 开发指南 ## 🎯 概述 本项目现已支持 **Code First** 方式开发 API: 1. **后端**:使用 Swagger 注释从代码生成 OpenAPI 文档 2. **前端**:使用 Orval 从 OpenAPI 文档生成 TypeScript 客户端 --- ## 🛠️ 工具链 ### 后端 - **swaggo/swag**: 从 Go 代码注释生成 OpenAPI/Swagger 文档 - 文档:https://github.com/swaggo/swag ### 前端 - **Orval**: 从 OpenAPI 规范生成 TypeScript API 客户端 - 文档:https://orval.dev/ --- ## 📝 开发流程 ### 1. 后端:添加 Swagger 注释 #### 主程序注释 (cmd/api/main.go) ```go // @title OCDP Backend API // @version 1.0 // @description OCDP (Open Cloud Development Platform) Backend API // // @host localhost:8080 // @BasePath /api/v1 // // @securityDefinitions.apikey BearerAuth // @in header // @name Authorization package main ``` #### Handler 方法注释示例 ```go // ListArtifacts 列出 repository 中的所有 artifacts // @Summary 列出 Repository 中的所有 Artifacts // @Description 列出指定 Repository 中的所有 Artifact,支持按类型过滤 // @Tags Artifacts // @Accept json // @Produce json // @Param registry_id path string true "Registry ID" // @Param repository_name path string true "Repository Name (URL encoded)" // @Param media_type query string false "过滤类型 (all, chart, image, other)" default(all) // @Success 200 {array} dto.TagResponse // @Failure 500 {object} dto.ErrorResponse // @Router /registries/{registry_id}/repositories/{repository_name}/artifacts [get] func (h *ArtifactHandler) ListArtifacts(w http.ResponseWriter, r *http.Request) { // ... } ``` ### 2. 生成 OpenAPI 文档 ```bash # 在 backend 目录下运行 cd backend swag init -g cmd/api/main.go -o docs/swagger --parseDependency --parseInternal # 生成的文件在 docs/swagger/ 目录: # - swagger.json # - swagger.yaml # - docs.go ``` ### 3. 前端:重新生成 API 客户端 ```bash # 在 frontend 目录下运行 cd frontend npm run openapi-gen # 或者 orval ``` 生成的文件在 `src/api/generated-orval/` 目录。 --- ## 🔄 完整工作流 ### 添加新 API 的步骤 #### 1. 后端开发 ```bash # 1.1 创建 DTO # internal/adapter/input/http/dto/new_feature_dto.go # 1.2 创建 Handler 并添加 Swagger 注释 # internal/adapter/input/http/rest/new_feature_handler.go # 1.3 注册路由 # cmd/api/main.go # 1.4 生成 OpenAPI 文档 cd backend swag init -g cmd/api/main.go -o docs/swagger --parseDependency --parseInternal # 1.5 复制到主文档 (可选) cp docs/swagger/swagger.yaml docs/openapi.yaml ``` #### 2. 前端开发 ```bash # 2.1 重新生成 API 客户端 cd frontend npm run openapi-gen # 2.2 使用生成的客户端 import { listArtifacts } from '@/api/generated-orval/api'; const data = await listArtifacts({ registryId: 'xxx', repositoryName: 'charts/nginx' }); ``` --- ## 📋 Swagger 注释速查 ### 常用标签 | 标签 | 说明 | 示例 | |------|------|------| | `@Summary` | 简短描述 | `@Summary 列出所有用户` | | `@Description` | 详细描述 | `@Description 返回系统中的所有用户列表` | | `@Tags` | API 分组 | `@Tags Users` | | `@Accept` | 接受的格式 | `@Accept json` | | `@Produce` | 返回的格式 | `@Produce json` | | `@Param` | 参数 | `@Param id path string true "User ID"` | | `@Success` | 成功响应 | `@Success 200 {object} dto.UserResponse` | | `@Failure` | 失败响应 | `@Failure 404 {object} dto.ErrorResponse` | | `@Router` | 路由定义 | `@Router /users/{id} [get]` | | `@Security` | 安全认证 | `@Security BearerAuth` | ### 参数类型 ```go // 路径参数 (path) @Param id path string true "User ID" // 查询参数 (query) @Param page query int false "Page number" default(1) @Param size query int false "Page size" default(20) // 请求体 (body) @Param request body dto.CreateUserRequest true "User data" // Header 参数 (header) @Param X-Request-ID header string false "Request ID" ``` ### 响应定义 ```go // 单个对象 @Success 200 {object} dto.UserResponse // 数组 @Success 200 {array} dto.UserResponse // 自定义响应 @Success 200 {object} map[string]interface{} // 多个可能的响应 @Success 200 {object} dto.UserResponse "Success" @Success 201 {object} dto.UserResponse "Created" @Failure 400 {object} dto.ErrorResponse "Bad Request" @Failure 404 {object} dto.ErrorResponse "Not Found" @Failure 500 {object} dto.ErrorResponse "Internal Error" ``` --- ## 🎯 最佳实践 ### 1. 命名规范 | 层级 | 风格 | 示例 | |------|------|------| | **路径变量** | snake_case | `{registry_id}`, `{repository_name}` | | **查询参数** | snake_case | `?media_type=chart` | | **JSON 字段** | camelCase | `repositoryName`, `mediaType` | | **Go 结构体** | PascalCase | `RepositoryName`, `MediaType` | ### 2. DTO 定义示例 ```go // ArtifactResponse Artifact 响应 type ArtifactResponse struct { RepositoryName string `json:"repositoryName"` // Go: PascalCase, JSON: camelCase Tag string `json:"tag"` Type string `json:"type"` Size int64 `json:"size"` CreatedAt string `json:"createdAt"` } ``` ### 3. 完整的 Handler 示例 ```go // GetArtifact 获取 artifact 详情 // @Summary 获取 Artifact 详情 // @Description 获取指定 Artifact 的详细信息 // @Tags Artifacts // @Accept json // @Produce json // @Param registry_id path string true "Registry ID" // @Param repository_name path string true "Repository Name (URL encoded)" // @Param reference path string true "Artifact Reference (tag or digest)" // @Success 200 {object} dto.ArtifactResponse // @Failure 404 {object} dto.ErrorResponse "Artifact not found" // @Failure 500 {object} dto.ErrorResponse "Internal server error" // @Router /registries/{registry_id}/repositories/{repository_name}/artifacts/{reference} [get] func (h *ArtifactHandler) GetArtifact(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) registryID := vars["registry_id"] repositoryName := vars["repository_name"] reference := vars["reference"] artifact, err := h.artifactService.GetArtifact(r.Context(), registryID, repositoryName, reference) if err != nil { respondError(w, http.StatusNotFound, "Artifact not found", err.Error()) return } response := &dto.ArtifactResponse{ RepositoryName: artifact.Repository, Tag: artifact.Tag, Digest: artifact.Digest, Type: string(artifact.Type), Size: artifact.Size, CreatedAt: artifact.CreatedAt.Format("2006-01-02T15:04:05Z07:00"), } respondJSON(w, http.StatusOK, response) } ``` --- ## 🔧 故障排除 ### 问题 1: swag 命令未找到 ```bash # 解决方案:安装 swag go install github.com/swaggo/swag/cmd/swag@latest # 确保 $GOPATH/bin 在 PATH 中 export PATH=$PATH:$(go env GOPATH)/bin ``` ### 问题 2: 生成的文档不完整 ```bash # 确保使用了正确的参数 swag init -g cmd/api/main.go -o docs/swagger --parseDependency --parseInternal # 检查注释格式是否正确 # 注释必须紧邻函数定义,中间不能有空行 ``` ### 问题 3: 前端客户端生成失败 ```bash # 检查 OpenAPI 文档是否有效 cd frontend npx @apidevtools/swagger-cli validate ../backend/docs/openapi.yaml # 清理并重新生成 rm -rf src/api/generated-orval npm run openapi-gen ``` --- ## 📚 参考资源 - **Swaggo 文档**: https://github.com/swaggo/swag - **Swaggo 声明式注释**: https://github.com/swaggo/swag#declarative-comments-format - **Orval 文档**: https://orval.dev/ - **OpenAPI 规范**: https://swagger.io/specification/ --- ## ✅ 当前状态 ### 已完成 - [x] 安装 swag 工具 - [x] 添加主程序 Swagger 注释 - [x] 为 Artifact Handler 添加完整注释 - [x] 生成 OpenAPI 文档 - [x] 前端配置 Orval - [x] 重新生成前端客户端 ### 待完成 (可选) - [ ] 为其他 Handler 添加 Swagger 注释 - [ ] Auth Handler - [ ] Cluster Handler - [ ] Registry Handler - [ ] Instance Handler - [ ] Monitoring Handler - [ ] 添加更详细的错误响应定义 - [ ] 添加请求/响应示例 - [ ] 配置 CI/CD 自动生成文档 --- ## 🎉 总结 现在项目支持 Code First 开发流程: 1. **后端开发者**:写代码 + 注释 → 生成 OpenAPI 2. **前端开发者**:使用 OpenAPI → 生成 TypeScript 客户端 3. **文档自动同步**:代码即文档,保证一致性 这确保了 API 文档始终与代码保持同步!✨