Files
carrotskin/API文档.md

332 lines
9.2 KiB
Markdown
Raw Normal View History

# CarrotSkin API 文档基于后端代码2026-07 修订)
> 本文档由后端 `internal/handler/*.go` + `internal/types/common.go` 直接整理而来,
> 是前后端契约的唯一事实来源。所有路径以 `/api/v1` 为前缀Yggdrasil / CSL 除外)。
## 通用约定
### 统一响应格式
成功:
```json
{ "code": 200, "message": "操作成功", "data": <任意> }
```
错误:
```json
{ "code": <非200>, "message": "<错误描述>", "error": "<仅非生产环境返回>" }
```
常用状态码:`200 成功` / `201 创建成功` / `400 参数错误` / `401 未授权` / `403 禁止` / `404 不存在` / `500 服务器错误`
### 认证
- 除"无需认证"标注的接口外,所有 `/user/*``/profile` 写操作、`/texture` 写操作均需在请求头携带:
`Authorization: Bearer <jwt_token>`
- JWT 通过登录或注册接口获取。
### 分页
- 请求参数:`page`(页码,默认 1`page_size`(每页数量,默认 20
- 响应数据形态(注意:后端返回的字段名是 **`per_page`**,且 **不含 `total_pages`**
```json
{
"code": 200,
"message": "操作成功",
"data": {
"list": [ ... ],
"total": 100,
"page": 1,
"per_page": 20
}
}
```
---
## 一、认证 `/auth`(无需 JWT
### 1. 用户注册
- `POST /api/v1/auth/register`
- Body
```json
{
"username": "newuser",
"email": "user@example.com",
"password": "password123",
"verification_code": "123456",
"captcha_id": "uuid-xxxx",
"avatar": "https://example.com/a.png"
}
```
- `username` 350 字符;`password` 6128`verification_code` 必填 6 位;
- `captcha_id` 必填(来自 `POST /captcha/verify` 后透传的 `captchaId`
- `avatar` 可选,必须是合法 URL。
- 响应 `data`
```json
{
"token": "<jwt>",
"user_info": {
"id": 1, "username": "newuser", "email": "user@example.com",
"avatar": "", "points": 0, "role": "user", "status": 1,
"last_login_at": null,
"created_at": "2026-07-08T10:00:00Z",
"updated_at": "2026-07-08T10:00:00Z"
}
}
```
### 2. 用户登录
- `POST /api/v1/auth/login`
- Body
```json
{ "username": "newuser 或 user@example.com", "password": "password123" }
```
- 响应 `data`:同注册(`{ token, user_info }`)。
### 3. 发送邮箱验证码
- `POST /api/v1/auth/send-code`
- Body
```json
{ "email": "user@example.com", "type": "register | reset_password | change_email" }
```
- 响应 `data``{ "message": "验证码已发送,请查收邮件" }`
### 4. 重置密码
- `POST /api/v1/auth/reset-password`
- Body
```json
{
"email": "user@example.com",
"verification_code": "123456",
"new_password": "newpassword123"
}
```
- 响应 `data``{ "message": "密码重置成功" }`
---
## 二、用户 `/user`(需 JWT
### 5. 获取当前用户信息
- `GET /api/v1/user/profile`
- 响应 `data``UserInfo`(同注册返回的 `user_info`)。
### 6. 更新用户信息(密码 / 头像 URL
- `PUT /api/v1/user/profile`
- Body
```json
{
"avatar": "https://example.com/a.png", // 可选,更新头像 URL
"old_password": "oldpassword123", // 修改密码时必填
"new_password": "newpassword123" // 6128
}
```
- 响应 `data`:更新后的 `UserInfo`
### 7. 上传头像文件
- `POST /api/v1/user/avatar/upload`multipart/form-data
- 字段:`file`图片文件≤10MB
- 响应 `data`
```json
{ "avatar_url": "https://.../avatar.png", "user": { ...UserInfo } }
```
### 8. 更新头像 URL外部 URL
- `PUT /api/v1/user/avatar?avatar_url=<url>`
- 响应 `data``UserInfo`
### 9. 更换邮箱
- `POST /api/v1/user/change-email`
- Body
```json
{ "new_email": "new@example.com", "verification_code": "123456" }
```
- 响应 `data`:更换后的 `UserInfo`(新邮箱已生效)。
### 10. 重置 Yggdrasil 密码
- `POST /api/v1/user/yggdrasil-password/reset`
- 响应 `data``{ "password": "<新的Yggdrasil密码>" }`
### 11. 获取用户公开信息
- `GET /api/v1/users/public?username=<name>``?id=<id>`(无需 JWT
- 响应 `data`
```json
{
"id": 1, "username": "testuser", "avatar": "",
"points": 100, "role": "user", "status": 1,
"created_at": "2026-07-01T10:00:00Z"
}
```
---
## 三、材质 `/texture`
### 12. 搜索材质(公开,无需 JWT
- `GET /api/v1/texture`
- Query`keyword` / `type=SKIN|CAPE` / `public_only=true` / `page` / `page_size`
- 响应 `data`:分页结构 `{ list: TextureInfo[], total, page, per_page }`
### 13. 获取材质详情(公开)
- `GET /api/v1/texture/:id`
- 响应 `data``TextureInfo`
### 14. 上传材质(需 JWTmultipart
- `POST /api/v1/texture/upload`
- formData`file`(PNG, ≤32MB)、`name`(必填)、`description``type=SKIN|CAPE``is_public``is_slim`
- 响应 `data``TextureInfo`
### 15. 更新材质(需 JWT
- `PUT /api/v1/texture/:id`
- Body
```json
{ "name": "新名称", "description": "新描述", "is_public": true }
```
- `is_public` 后端为 `*bool`,传 `true/false` 会更新;不传保持不变。
- 响应 `data``TextureInfo`
### 16. 删除材质(需 JWT
- `DELETE /api/v1/texture/:id`
- 响应 `data``null`
### 17. 切换收藏(需 JWT
- `POST /api/v1/texture/:id/favorite`
- 响应 `data``{ "is_favorited": true }`
### 18. 我的上传(需 JWT
- `GET /api/v1/texture/my?page=1&page_size=20`
- 响应 `data`:分页结构。
### 19. 我的收藏(需 JWT
- `GET /api/v1/texture/favorites?page=1&page_size=20`
- 响应 `data`:分页结构。
#### TextureInfo 字段
`id, uploader_id, uploader_username, name, description(omitempty), type(SKIN|CAPE), url, hash, size, is_public, download_count, favorite_count, is_slim, status, created_at, updated_at`
---
## 四、档案 `/profile`
> ⚠️ **后端当前 `PUT /profile/:uuid` 不支持解除皮肤/披风绑定**
> `UpdateProfileRequest.SkinID / CapeID` 为 `*int64`,仅当非 nil 时才更新;
> 传 `null` 与字段缺失都会被 Go 反序列化为 `nil`,二者无法区分,均被忽略。
> 因此前端要"移除角色皮肤",需要后端先支持(详见下方《待补齐》)。
### 20. 获取档案列表(需 JWT
- `GET /api/v1/profile``GET /api/v1/profile/`
- 响应 `data``ProfileInfo[]`
### 21. 创建档案(需 JWT
- `POST /api/v1/profile``POST /api/v1/profile/`
- Body`{ "name": "PlayerName" }`116 字符)
- 响应 `data``ProfileInfo`
### 22. 获取档案详情(公开)
- `GET /api/v1/profile/:uuid`
- 响应 `data``ProfileInfo`
### 23. 更新档案(需 JWT
- `PUT /api/v1/profile/:uuid`
- Body
```json
{ "name": "NewName", "skin_id": 1, "cape_id": 2 }
```
- 当前实现:`skin_id/cape_id` 传数字会设置;传 null / 缺失均被忽略(无法清空)。
- 响应 `data``ProfileInfo`
### 24. 删除档案(需 JWT
- `DELETE /api/v1/profile/:uuid`
- 响应 `data``{ "message": "删除成功" }`
#### ProfileInfo 字段
`uuid, user_id, name, skin_id(omitempty,可空), cape_id(omitempty,可空), last_used_at(omitempty), created_at, updated_at`
---
## 五、滑动验证码 `/captcha`(无需 JWT
### 25. 生成滑动验证码
- `GET /api/v1/captcha/generate`
- 响应(注意:此接口的响应是直接对象,未包裹 `data`
```json
{
"code": 200,
"data": {
"masterImage": "<base64 主图>",
"tileImage": "<base64 滑块图>",
"captchaId": "<进程ID注册时需要>",
"y": <缺口纵坐标>
}
}
```
### 26. 校验滑动验证码
- `POST /api/v1/captcha/verify`
- Body`{ "captchaId": "<id>", "dx": <横坐标> }`
- 响应:`{ "code": 200, "msg": "验证成功" }``{ "code": 400, "msg": "验证失败,请重试" }`
---
## 六、Yggdrasil API `/api/yggdrasil`(独立前缀,供 MC 客户端使用)
- `GET /api/yggdrasil` —— 元数据
- `POST /api/yggdrasil/minecraftservices/player/certificates`
- `POST /api/yggdrasil/authserver/authenticate`
- `POST /api/yggdrasil/authserver/validate`
- `POST /api/yggdrasil/authserver/refresh`
- `POST /api/yggdrasil/authserver/invalidate`
- `POST /api/yggdrasil/authserver/signout`
- `GET /api/yggdrasil/sessionserver/session/minecraft/profile/:uuid`
- `POST /api/yggdrasil/sessionserver/session/minecraft/join`
- `GET /api/yggdrasil/sessionserver/session/minecraft/hasJoined`
- `POST /api/yggdrasil/api/profiles/minecraft`
## 七、CustomSkinAPI `/api/v1/csl`(公开)
- `GET /api/v1/csl/:username` —— 获取玩家信息 JSON
- `GET /api/v1/csl/textures/:hash` —— 获取资源文件
## 八、管理员 `/api/v1/admin`(需 JWT + 管理员)
- `GET /admin/users``GET /admin/users/:id`
- `PUT /admin/users/role``PUT /admin/users/status`
- `GET /admin/textures``DELETE /admin/textures/:id`
- `GET /admin/permissions`
---
## 待补齐(后端缺陷,影响前端可用性)
1. **`PUT /profile/:uuid` 不支持清空 skin/cape**
现状:`SkinID/CapeID *int64` 无法区分"未传"与"显式 null"。
建议:改用 `json.RawMessage` 区分三种语义(缺失=不修改 / null=清空 / 数字=设置),
或新增 `remove_skin` / `remove_cape` 布尔字段。前端"移除角色皮肤"依赖此能力。