8.4 KiB
8.4 KiB
Code First API 开发指南
🎯 概述
本项目现已支持 Code First 方式开发 API:
- 后端:使用 Swagger 注释从代码生成 OpenAPI 文档
- 前端:使用 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)
// @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 方法注释示例
// 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 文档
# 在 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 客户端
# 在 frontend 目录下运行
cd frontend
npm run openapi-gen
# 或者
orval
生成的文件在 src/api/generated-orval/ 目录。
🔄 完整工作流
添加新 API 的步骤
1. 后端开发
# 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. 前端开发
# 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 |
参数类型
// 路径参数 (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"
响应定义
// 单个对象
@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 定义示例
// 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 示例
// 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 命令未找到
# 解决方案:安装 swag
go install github.com/swaggo/swag/cmd/swag@latest
# 确保 $GOPATH/bin 在 PATH 中
export PATH=$PATH:$(go env GOPATH)/bin
问题 2: 生成的文档不完整
# 确保使用了正确的参数
swag init -g cmd/api/main.go -o docs/swagger --parseDependency --parseInternal
# 检查注释格式是否正确
# 注释必须紧邻函数定义,中间不能有空行
问题 3: 前端客户端生成失败
# 检查 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/
✅ 当前状态
已完成
- 安装 swag 工具
- 添加主程序 Swagger 注释
- 为 Artifact Handler 添加完整注释
- 生成 OpenAPI 文档
- 前端配置 Orval
- 重新生成前端客户端
待完成 (可选)
- 为其他 Handler 添加 Swagger 注释
- Auth Handler
- Cluster Handler
- Registry Handler
- Instance Handler
- Monitoring Handler
- 添加更详细的错误响应定义
- 添加请求/响应示例
- 配置 CI/CD 自动生成文档
🎉 总结
现在项目支持 Code First 开发流程:
- 后端开发者:写代码 + 注释 → 生成 OpenAPI
- 前端开发者:使用 OpenAPI → 生成 TypeScript 客户端
- 文档自动同步:代码即文档,保证一致性
这确保了 API 文档始终与代码保持同步!✨