马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
API 接口筹划
Go-ES 项目提供了一套完整的 RESTful API,用于产品管理和搜索。本文档详细先容了 API 的筹划原则、接口定义和使用方法。
API 筹划原则
本项目标 API 筹划遵照以下原则:
- RESTful 风格:使用标准的 HTTP 方法体现操作类型
- 资源导向:API 路径以资源名词为中央
- JSON 格式:请求和相应均使用 JSON 格式
- 版本控制:API 路径包含版本号
- 统一错误处理:使用一致的错误相应格式
- 自文档化:使用 Swagger 注解自动天生 API 文档
API 底子信息
- 底子路径:/api/v1
- 内容类型:application/json
- 认证方式:API Key(通过 Authorization 头)
API 端点概览
方法路径描述POST/products创建产品GET/products获取产品列表GET/products/{id}获取产品详情PUT/products/{id}更新产品DELETE/products/{id}删除产品GET/products/category/{category}获取指定种别产品GET/products/search搜索产品POST/products/reindex重修产品索引 API 详细分析
1. 创建产品
请求:
- POST /api/v1/products
- Content-Type: application/json
- {
- "name": "示例产品",
- "description": "这是一个示例产品",
- "price": 99.99,
- "category": "电子产品",
- "tags": ["新品", "热销"]
- }
复制代码 相应:
- HTTP/1.1 201 Created
- Content-Type: application/json
- {
- "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
- "name": "示例产品",
- "description": "这是一个示例产品",
- "price": 99.99,
- "category": "电子产品",
- "tags": ["新品", "热销"],
- "created_at": "2023-05-01T12:00:00Z",
- "updated_at": "2023-05-01T12:00:00Z"
- }
复制代码 处理逻辑:
- func (h *ProductHandler) Create(c *gin.Context) {
- var req dto.CreateProductRequest
- if err := c.ShouldBindJSON(&req); err != nil {
- c.JSON(http.StatusBadRequest, gin.H{"error": "无效的请求数据"})
- return
- }
- product, err := h.productAppService.CreateProduct(c.Request.Context(), &req)
- if err != nil {
- c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("创建产品失败: %v", err)})
- return
- }
- c.JSON(http.StatusCreated, product)
- }
复制代码 2. 获取产品列表
请求:
- GET /api/v1/products?page=1&size=10
复制代码 相应:
- HTTP/1.1 200 OK
- Content-Type: application/json
- {
- "total": 100,
- "page": 1,
- "page_size": 10,
- "products": [
- {
- "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
- "name": "示例产品",
- "description": "这是一个示例产品",
- "price": 99.99,
- "category": "电子产品",
- "tags": ["新品", "热销"],
- "created_at": "2023-05-01T12:00:00Z",
- "updated_at": "2023-05-01T12:00:00Z"
- },
- // ... 更多产品
- ]
- }
复制代码 处理逻辑:
- func (h *ProductHandler) List(c *gin.Context) {
- page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
- size, _ := strconv.Atoi(c.DefaultQuery("size", "10"))
- products, err := h.productAppService.ListProducts(c.Request.Context(), page, size)
- if err != nil {
- c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("获取产品列表失败: %v", err)})
- return
- }
- c.JSON(http.StatusOK, products)
- }
复制代码 3. 获取产品详情
请求:
- GET /api/v1/products/f47ac10b-58cc-4372-a567-0e02b2c3d479
复制代码 相应:
- HTTP/1.1 200 OK
- Content-Type: application/json
- {
- "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
- "name": "示例产品",
- "description": "这是一个示例产品",
- "price": 99.99,
- "category": "电子产品",
- "tags": ["新品", "热销"],
- "created_at": "2023-05-01T12:00:00Z",
- "updated_at": "2023-05-01T12:00:00Z"
- }
复制代码 处理逻辑:
- func (h *ProductHandler) Get(c *gin.Context) {
- id := c.Param("id")
- if id == "" {
- c.JSON(http.StatusBadRequest, gin.H{"error": "产品ID不能为空"})
- return
- }
- product, err := h.productAppService.GetProduct(c.Request.Context(), id)
- if err != nil {
- if err.Error() == "产品不存在" {
- c.JSON(http.StatusNotFound, gin.H{"error": "产品不存在"})
- return
- }
- c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("获取产品失败: %v", err)})
- return
- }
- c.JSON(http.StatusOK, product)
- }
复制代码 4. 搜索产品
请求:
- GET /api/v1/products/search?q=手机&category=电子产品&page=1&size=10
复制代码 相应:
- HTTP/1.1 200 OK
- Content-Type: application/json
- {
- "total": 5,
- "page": 1,
- "page_size": 10,
- "products": [
- {
- "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
- "name": "高端智能手机",
- "description": "这是一款功能强大的智能手机",
- "price": 3999.99,
- "category": "电子产品",
- "tags": ["手机", "智能设备"],
- "created_at": "2023-05-01T12:00:00Z",
- "updated_at": "2023-05-01T12:00:00Z"
- },
- // ... 更多产品
- ]
- }
复制代码 处理逻辑:
- func (h *ProductHandler) Search(c *gin.Context) {
- var searchReq dto.SearchProductRequest
- if err := c.ShouldBindQuery(&searchReq); err != nil {
- c.JSON(http.StatusBadRequest, gin.H{"error": "无效的搜索参数"})
- return
- }
- products, err := h.productAppService.SearchProducts(c.Request.Context(), &searchReq)
- if err != nil {
- c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("搜索产品失败: %v", err)})
- return
- }
- c.JSON(http.StatusOK, products)
- }
复制代码 请求与相应模型
请求模型
创建产品请求
- // CreateProductRequest 创建产品请求
- type CreateProductRequest struct {
- Name string `json:"name" binding:"required"`
- Description string `json:"description"`
- Price float64 `json:"price" binding:"required,gt=0"`
- Category string `json:"category" binding:"required"`
- Tags []string `json:"tags"`
- }
复制代码 更新产品请求
- // UpdateProductRequest 更新产品请求
- type UpdateProductRequest struct {
- Name string `json:"name" binding:"required"`
- Description string `json:"description"`
- Price float64 `json:"price" binding:"required,gt=0"`
- Category string `json:"category" binding:"required"`
- Tags []string `json:"tags"`
- }
复制代码 搜索产品请求
- // SearchProductRequest 搜索产品请求
- type SearchProductRequest struct {
- Keyword string `form:"q"`
- Category string `form:"category"`
- Page int `form:"page,default=1"`
- PageSize int `form:"size,default=10"`
- }
复制代码 相应模型
产品相应
- // ProductResponse 产品响应
- type ProductResponse struct {
- ID string `json:"id"`
- Name string `json:"name"`
- Description string `json:"description"`
- Price float64 `json:"price"`
- Category string `json:"category"`
- Tags []string `json:"tags"`
- CreatedAt time.Time `json:"created_at"`
- UpdatedAt time.Time `json:"updated_at"`
- }
复制代码 产品列表相应
- // ProductListResponse 产品列表响应
- type ProductListResponse struct {
- Total int64 `json:"total"`
- Page int `json:"page"`
- PageSize int `json:"page_size"`
- Products []ProductResponse `json:"products"`
- }
复制代码 错误处理
API 使用统一的错误相应格式:
常见的错误相应包括:
- 400 Bad Request: 请求参数无效
- 404 Not Found: 请求的资源不存在
- 500 Internal Server Error: 服务器内部错误
API 文档天生
本项目使用 Swagger 自动天生 API 文档。API 处理器中的注解如下所示:
- // Create 创建产品
- // @Summary 创建新产品
- // @Description 创建一个新的产品并索引到Elasticsearch
- // @Tags 产品
- // @Accept json
- // @Produce json
- // @Param product body dto.CreateProductRequest true "产品信息"
- // @Success 201 {object} dto.ProductResponse
- // @Failure 400 {object} map[string]string "错误信息"
- // @Failure 500 {object} map[string]string "错误信息"
- // @Router /products [post]
- func (h *ProductHandler) Create(c *gin.Context) {
- // 实现逻辑...
- }
复制代码 使用 Swagger 文档
- http://localhost:8080/swagger/index.html
复制代码
- 在 Swagger UI 界面中可以:
- 欣赏所有 API 端点
- 检察请求参数和相应格式
- 直接在欣赏器中测试 API
API 路由注册
所有 API 路由在 interfaces/api/router/router.go 中注册:
- // SetupRouter 设置路由
- func SetupRouter(engine *gin.Engine, productHandler *handler.ProductHandler) {
- // 设置中间件
- engine.Use(gin.Logger())
- engine.Use(gin.Recovery())
- engine.Use(middleware.Cors())
- // 添加Swagger
- engine.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerfiles.Handler))
- // API 路由组
- api := engine.Group("/api/v1")
- {
- // 产品相关路由
- products := api.Group("/products")
- {
- products.POST("", productHandler.Create)
- products.GET("", productHandler.List)
- products.GET("/:id", productHandler.Get)
- products.PUT("/:id", productHandler.Update)
- products.DELETE("/:id", productHandler.Delete)
- products.GET("/category/:category", productHandler.ListByCategory)
- products.GET("/search", productHandler.Search)
- products.POST("/reindex", productHandler.ReindexAll)
- }
- }
- }
复制代码 跨域处理
API 支持跨域请求,通过自定义中间件实现:
- // Cors 添加CORS头
- func Cors() gin.HandlerFunc {
- return func(c *gin.Context) {
- c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
- c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
- c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
- c.Writer.Header().Set("Access-Control-Max-Age", "86400")
- // 处理OPTIONS请求
- if c.Request.Method == "OPTIONS" {
- c.AbortWithStatus(200)
- return
- }
- // 处理请求
- c.Next()
- }
- }
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |