--- tags: [后端, API, RESTful, 设计] create time: 2026-04-24 18:41 --- # API 设计 ## 概述 API(Application Programming Interface)是前后端协作的契约。好的 API 设计让前端开发者一看就懂、一用就会。差的 API 设计会让协作效率大幅下降。 思考题:设计一个 API 时,是应该"让所有人都符合你的设计"还是"让设计迁就所有使用场景"?这两者的边界在哪里? ## 正文 ### 1. RESTful API 设计规范 **资源命名:** - URL 用名词复数,不用动词 - 层级结构表示从属关系 - 查询参数用于筛选和排序 ``` GET /api/users → 获取用户列表 GET /api/users/5 → 获取用户 5 的详情 GET /api/users/5/posts → 获取用户 5 的所有文章 GET /api/users?role=admin → 筛选管理员用户 GET /api/users?sort=-created_at → 按创建时间倒序 GET /api/users?page=2&limit=20 → 分页 ``` ### 2. 标准响应格式 ```json // 成功响应(200 OK) { "code": 0, "message": "success", "data": { "id": 1, "name": "Alice", "email": "alice@example.com" } } // 成功响应(201 Created) { "code": 0, "message": "created", "data": { "id": 5, ... } } // 错误响应(4xx / 5xx) { "code": 1001, "message": "用户不存在", "data": null } ``` > **提问:** 错误码设计成数字好还是字符串好?数字更紧凑但可读性差,字符串更直观但传输量大。你怎么权衡? ### 3. 常见错误码设计 | code | HTTP 状态码 | 含义 | |------|-------------|------| | 0 | 200 | 成功 | | 1001 | 404 | 资源不存在 | | 1002 | 400 | 参数校验失败 | | 1003 | 401 | 未认证 | | 1004 | 403 | 无权限 | | 1005 | 429 | 请求过于频繁 | | 2001 | 500 | 服务器内部错误 | ### 4. 分页设计 ``` GET /api/users?page=1&limit=20 响应: { "code": 0, "data": [...], // 当前页数据 "pagination": { "page": 1, "limit": 20, "total": 100, "total_pages": 5 } } ``` > **核心概念:** 客户端分页 vs 服务端分页。大数据量时必须服务端分页,否则性能灾难。 ### 5. 版本控制 ``` 方案一:URL 路径(推荐) /api/v1/users /api/v2/users 方案二:请求头 Accept: application/vnd.api.v1+json ``` ### 6. Go 后端 API 示例 ```go package main import ( "encoding/json" "net/http" "time" ) // 统一响应结构 type APIResponse struct { Code int `json:"code"` Message string `json:"message"` Data interface{} `json:"data"` } func writeJSON(w http.ResponseWriter, status int, resp APIResponse) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) json.NewEncoder(w).Encode(resp) } // 处理用户列表 func userListHandler(w http.ResponseWriter, r *http.Request) { // 1. 解析查询参数 page, _ := strconv.Atoi(r.URL.Query().Get("page")) if page < 1 { page = 1 } limit, _ := strconv.Atoi(r.URL.Query().Get("limit")) if limit == 0 { limit = 20 } // 2. 查询数据库(省略) users, total := getUsersFromDB(page, limit) // 3. 返回统一格式 writeJSON(w, http.StatusOK, APIResponse{ Code: 0, Message: "success", Data: map[string]interface{}{ "users": users, "pagination": map[string]int{ "page": page, "limit": limit, "total": total, "pages": (total + limit - 1) / limit, }, }, }) } ``` ```mermaid graph TD A[HTTP Request] --> B{方法检查} B -->|GET| C[解析查询参数] B -->|POST| D[解析请求体] C --> E[参数校验] D --> E E --> F{校验通过?} F -->|否| G[返回 400 + 错误信息] F -->|是| H[查询/操作数据库] H --> I{操作成功?} I -->|否| J[返回对应错误码] I -->|是| K[返回 200/201 + 数据] ``` ## 关联笔记 - [[HTTP 协议]] — API 设计的基础是理解 HTTP - [[Go 后端基础]] — Go 实现 API 的具体方法 - [[数据库基础]] — API 的数据来源 - [[30.areas/finance/Investment lessons/2024.Current trading lessons.md]]