创建仓库

This commit is contained in:
2025-12-11 07:24:36 +08:00
commit 0d81c1792d
128 changed files with 15104 additions and 0 deletions

View File

@@ -0,0 +1,183 @@
---
tags: []
aliases:
- 🔌 AI 辅助 API 定义方法论 (v1.0)
date created: 星期日, 十二月 7日 2025, 11:43:04 晚上
date modified: 星期日, 十二月 7日 2025, 11:44:30 晚上
---
# 🔌 AI 辅助 API 定义方法论 (v1.0)
**核心理念:**
1. **DTO 先行:** 先定义输入 (Request) 和输出 (Response) 的数据结构,再写业务逻辑。
2. **注释即文档:** 利用 AI 自动生成繁琐的 Swagger 注释 (`@Summary`, `@Param`…)。
3. **契约可视化:** 在写第一行逻辑代码前,先能在 Swagger UI 上看到接口定义。
---
## 阶段一API 资源设计 (Design)
**目的:** 确定 URL 路径、HTTP 方法和 JSON 数据结构,确保符合 RESTful 规范。
### 🤖 通用 Prompt (复制使用)
```Markdown
你现在是我的 **API 架构师**
我们已经完成了数据库设计,现在需要设计 `{业务模块}` (例如: User) 的 API 接口。
**输入上下文:**
1. **业务实体:** `{粘贴 User 的 Entity 代码或 SQL}`
2. **功能需求:** 注册、登录、获取个人资料、更新资料。
**请输出 API 设计方案 (表格形式):**
1. **Method:** GET/POST/PUT/PATCH/DELETE
2. **Path:** URL 路径 (使用 RESTful 风格, 如 `/api/v1/users/:id`)
3. **Request Body:** 关键字段 (JSON 示例)
4. **Response:** 成功返回的数据结构 (JSON 示例)
**设计原则:**
- 使用统一的响应信封: `{ "code": 200, "msg": "success", "data": ... }`
- 更新操作区分 PUT (全量) 和 PATCH (局部)。
- 敏感字段 (密码) 绝对不能出现在 Response 中。
```
---
## 阶段二:生成 DTO 结构体 (Contract Definition)
**目的:** 将 JSON 设计转化为 Go 结构体。这是前后端交互的**法律条文**。
**工程位置:** `internal/api/request/` (入参) 和 `internal/api/response/` (出参)。
### 🤖 通用 Prompt (复制使用)
```Markdown
设计确认通过。请基于上述设计,生成 Go 语言的 **DTO (Data Transfer Object) 结构体**
**技术约束:**
1. 使用 `gin` 的 binding 标签进行参数校验 (如 `binding:"required,email"`).
2. 使用 `json` 标签定义字段名 (camelCase).
3. **分离 Request 和 Response:** 不要直接复用数据库 Entity必须定义独立的 DTO。
**输出代码要求:**
- `UserRegisterReq` (包含 Email, Password, ConfirmPassword)
- `UserLoginReq`
- `UserProfileResp` (不含密码,转换时间格式)
请直接输出 Go 代码,放在 package `user_dto` 下。
```
---
## 阶段三:生成 Handler 骨架与 Swagger 注释 (Implementation Skeleton)
**目的:** 这是一个“体力活”。AI 最擅长帮我们要写几十行的 Swagger 注释。
**工程位置:** `internal/user/handler.go`
### 🤖 通用 Prompt (复制使用)
```Markdown
现在请生成 Gin Handler 的**代码骨架**,并附带完整的 **Swagger 注释**
**输入:**
DTO 结构体已定义: `UserRegisterReq`, `UserProfileResp`...
**输出要求:**
1. **Swagger 注释:** 必须包含 `@Summary`, `@Tags`, `@Accept json`, `@Produce json`, `@Param`, `@Success`, `@Router`
2. **Handler 签名:** 接收 `*gin.Context`
3. **参数绑定:** 在 Handler 内部生成 `ShouldBindJSON` 代码块。
4. **占位返回:** 暂时直接返回 Mock 数据或 `http.StatusOK`**不要写具体的 Service 业务逻辑**。
**示例注释格式:**
// Register
// @Summary 用户注册
// @Tags User
// @Accept json
// @Produce json
// @Param request body user_dto.UserRegisterReq true "注册信息"
// @Success 200 {object} app.Result{data=user_dto.UserProfileResp}
// @Router /api/v1/auth/register [post]
func (h *UserHandler) Register(c *gin.Context) { ... }
```
---
## 🏗️ 工程落地操作指南 (How to Execute)
### 1. 文件安放位置
不要乱放,严格遵守目录结构:
```Plaintext
internal/
├── api/ # [Contract Layer] 存放 DTO
│ ├── request/ # 入参结构体
│ │ └── user_req.go
│ └── response/ # 出参结构体
│ └── user_resp.go
└── user/ # [Domain Layer]
└── handler.go # 控制器 (含 Swagger 注释)
```
### 2. 实操步骤 (SOP)
#### Step 1: 定义 DTO (The Contract)
- 运行阶段二的 Prompt。
- 将代码复制到 `internal/api/request/user_req.go`
- **这一步完成了,就代表你和前端的接口契约签好了。**
#### Step 2: 编写 Handler 骨架 (The Skeleton)
- 运行阶段三的 Prompt。
- 将代码复制到 `internal/user/handler.go`
- 确保此时代码能编译通过(缺少 Service 调用没关系,先留空)。
#### Step 3: 生成 Swagger 文档 (Generate)
这是验证的关键一步。我们需要使用 `swag` 工具扫描你的注释并生成 JSON 文档。
**在终端执行:**
```Bash
swag init -g cmd/server/main.go -o docs
```
_(注意: `-g` 指向你的 main 函数入口swag 会从那里开始递归扫描)_
#### Step 4: 启动服务并验证 (Verify)
- 运行 `go run cmd/server/main.go`
- 打开浏览器访问 `http://localhost:8080/swagger/index.html`
- **你看到的界面,就是你刚刚定义的“接口合同”。**
---
## 💡 常见问题与技巧
**Q: 为什么不直接用 Entity 作为 Response**
- **A:** **千万别这么做。** Entity 包含 `password_hash`,包含 `deleted_at`这些都不该给前端。DTO 让你有精准控制返回字段的权利。
**Q: Swagger 注释太难写了,容易写错格式。**
- **A:** 这就是为什么要用 AI 的原因。**永远不要手写 Swagger 注释**。把 Handler 代码发给 AI对它说“_请帮我补全 Swagger 注释,参数是 X返回值是 Y_”。
**Q: 接口变了怎么办?**
- **A:**
1. 修改 DTO (Go Struct)。
2. 让 AI 更新 Handler 里的 Swagger 注释。
3. 运行 `swag init`
4. 文档自动更新。
---
**总结你的下一步行动:**
1. **DTO 设计:** 使用 Prompt 生成 `User` 相关的 Request/Response 结构体。
2. **骨架生成:** 使用 Prompt 生成带有 Swagger 注释的 `UserHandler`
3. **文档验证:** 运行 `swag init` 并在浏览器中确认接口文档无误。

View File

@@ -0,0 +1,174 @@
---
tags: []
aliases:
- 1. 接口版本控制策略 (API Versioning Strategy)
date created: 星期日, 十二月 7日 2025, 11:38:52 晚上
date modified: 星期日, 十二月 7日 2025, 11:42:18 晚上
---
# 七七八八的接口设计相关问题
## 1. 接口版本控制策略 (API Versioning Strategy)
**核心问题:** 当你发布了 V1 版本后,某天需要修改接口字段(比如把 `name` 拆分为 `first_name``last_name`),如何保证老版本的 App 不会崩溃?
**三种主流流派:**
1. **URI Path Versioning (推荐):**
- **格式:** `https://api.example.com/v1/users`
- **优点:** 直观、易于调试、缓存友好。这也是 GitHub, Twitter, Google API 采用的主流方案。
- **落地:** 我们在 Gin 的 Router Group 中直接体现:
Go
```bash
v1 := r.Group("/api/v1")
{
v1.GET("/users", ...)
}
```
2. **Header Versioning:**
- **格式:** Header 中添加 `Accept: application/vnd.myapi.v1+json`
- **优点:** URL 干净。
- **缺点:** 调试麻烦(浏览器直接访问 URL 看不到结果CDN 缓存配置复杂。**不推荐 MVP 阶段使用。**
3. **Query Parameter:**
- **格式:** `/users?version=1`
- **评价:** 看起来很土,通常不用于 RESTful API。
**👉 你的策略:** 坚定选择 **URI Path Versioning (`/api/v1`)**。只在发生**破坏性变更 (Breaking Change)** 时才升级到 v2。新增字段不算破坏性变更不需要升级版本。
---
## 2. HTTP 方法的精准语义 (Verbs Semantics)
很多新手只会用 `GET` 和 `POST`。企业级 API 必须精准区分以下方法的含义:
|**方法**|**语义**|**幂等性 (Idempotency)**|**典型场景**|
|---|---|---|---|
|**GET**|获取资源|✅ 是|获取文章列表、详情|
|**POST**|新建资源|❌ 否|发布新文章、提交评论|
|**PUT**|**全量替换**资源|✅ 是|修改文章(客户端发送文章的完整 JSON没传的字段会被置空|
|**PATCH**|**局部更新**资源|❌ 否 (理论上)|修改文章状态(只传 `{"status": "published"}`,其他字段不变)|
|**DELETE**|删除资源|✅ 是|删除文章|
⚠️ 重点关注 PUT vs PATCH:
在 Go 语言中实现 PATCH 有点麻烦(因为 Go 的结构体默认值问题,你很难区分用户是传了 0 还是没传这个字段)。
- **最佳实践:** 对于 CMS 这种表单复杂的系统,**修改接口首选 `PUT` (全量)**,或者针对特定状态修改提供独立接口(如 `POST /articles/:id/publish`)。如果必须做 `PATCH`DTO 需使用指针类型 `*string` 来判断是否为 `nil`。
---
## 3. RESTful URL 设计模式 (Resource Naming)
**原则URL 中只出现名词,不出现动词。**
- ❌ **反例 (RPC 风格 - 不要这么做):**
- `/api/getUsers`
- `/api/createUser`
- `/api/deleteArticle?id=1`
- ✅ **正例 (REST 风格):**
- `GET /api/v1/users` (获取列表)
- `POST /api/v1/users` (创建)
- `DELETE /api/v1/articles/1` (删除 ID 为 1 的文章)
**复杂关系的嵌套设计:**
- _场景:_ 获取某篇文章下的评论。
- _设计:_ `GET /api/v1/articles/{article_id}/comments`
- _场景:_ 获取某个作者的所有文章。
- _设计:_ `GET /api/v1/users/{user_id}/articles`
---
## 4. 列表接口三剑客:分页、排序、筛选 (Pagination, Sorting, Filtering)
你的 CMS 一定会有“文章列表”页面,这个接口是最复杂的。不要为每种查询都写一个新接口,要设计一个**通用的查询接口**。
**最佳实践标准:**
1. **分页 (Pagination):**
- 使用 `page` (页码) 和 `page_size` (每页条数)。
- URL 示例: `/articles?page=2&page_size=20`
- **注意:** 要限制 `page_size` 的最大值(如 100防止恶意用户一次请求 100 万条数据把数据库打挂。
2. **排序 (Sorting):**
- 使用 `sort` 参数。`-` 代表降序,无符号代表升序。
- URL 示例: `/articles?sort=-created_at` (按创建时间倒序)
- URL 示例: `/articles?sort=view_count,-created_at` (先按浏览量升序,再按时间倒序)
3. **筛选 (Filtering):**
- 直接使用字段名作为参数。
- URL 示例: `/articles?category_id=1&status=published`
---
## 5. 状态码与错误处理 (Status Codes & Error Handling)
**不要永远只返回 200 OK**
前端开发最恨的就是HTTP 状态码是 200结果 Body 里写着 `{"code": 500, "msg": "Error"}`。这会让监控系统失效。
**你需要遵守的“HTTP 状态码地图”:**
- **2xx (成功):**
- `200 OK`: 通用成功。
- `201 Created`: 创建成功 (POST 返回)。
- `204 No Content`: 删除成功 (DELETE 返回,不带 Body)。
- **4xx (客户端错误 - 前端背锅):**
- `400 Bad Request`: 参数校验失败(如邮箱格式不对)。
- `401 Unauthorized`: 未登录/Token 过期。
- `403 Forbidden`: 登录了,但没权限(如普通用户想删文章)。
- `404 Not Found`: 资源不存在。
- **5xx (服务端错误 - 你背锅):**
- `500 Internal Server Error`: 代码崩了/数据库挂了。
统一错误响应格式 (JSON Envelope):
无论发生什么错误Body 必须保持结构一致,方便前端拦截:
JSON
```bash
{
"code": 40001, // 业务错误码 (你在 pkg/e 定义的)
"message": "标题已存在", // 给用户看的提示
"request_id": "abc-123" // 方便查日志的 Trace ID
}
```
---
## 6. 进阶知识:幂等性 (Idempotency)
**概念:** 用户因为网络卡顿,连续点击了 3 次“发布文章”按钮,你的系统会创建 1 篇文章还是 3 篇?
- **非幂等:** `POST`。点 3 次创建 3 篇。
- **幂等:** `PUT` / `DELETE`。改 3 次和改 1 次结果一样;删 3 次和删 1 次结果一样(都是没了)。
如何处理 POST 的幂等性?
对于关键业务(如支付、核心数据创建),通常要求前端在 Header 带一个 Idempotency-Key (UUID)。后端 Redis 记录这个 Key如果短时间内收到相同的 Key直接返回上次的结果不执行数据库插入。
(注MVP 阶段可以先不做,但面试或者做高可靠系统时必须知道)
---
## 总结:在你开始定义 API 之前
请在心中建立这套标准:
1. **URL:** `/api/v1/名词`
2. **Method:** 查询用 GET新建用 POST修改用 PUT删除用 DELETE。
3. **List:** 永远记得预留 `page`, `page_size`。
4. **Response:** 永远返回统一的 JSON 结构,报错必须用 4xx/5xx 状态码。
**准备好了吗?我们可以开始基于这些原则,设计 User 模块的 API 了。**