This repository has been archived on 2026-05-19. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files

183 lines
4.2 KiB
Markdown
Raw Permalink Normal View History

2026-04-24 23:45:19 +08:00
---
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]]