Files
carrotskin/API文档.md
Wuying Created Local Users 5f90f48a1c feat: 完成navbar隐藏优化和侧边栏冻结功能
- 优化navbar滚动隐藏逻辑,更敏感响应
- 添加返回顶部按钮,固定在右下角
- 实现profile页面侧边栏真正冻结效果
- 修复首页滑动指示器位置
- 优化整体布局确保首屏内容完整显示
2025-12-04 20:05:13 +08:00

20 KiB
Raw Blame History

CarrotSkin 后端 API 文档

概述

本文档总结了 CarrotSkin 后端 API主要关注前端需要的接口不包括 Yggdrasil 相关接口(除了更换 Yggdrasil 密码)。

基础信息

  • 基础URL: /api/v1
  • 认证方式: JWT Bearer Token
  • 数据格式: JSON
  • 字符编码: UTF-8

通用响应格式

所有API响应都遵循以下格式

{
  "code": 200,
  "message": "操作成功",
  "data": {
    // 具体数据内容
  }
}

分页响应格式:

{
  "code": 200,
  "message": "操作成功",
  "data": {
    "list": [],
    "total": 100,
    "page": 1,
    "page_size": 20,
    "total_pages": 5
  }
}

认证相关 API

1. 用户注册

  • URL: POST /api/v1/auth/register
  • 认证: 无需认证
  • 请求参数:
{
  "username": "newuser",          // 用户名3-50字符
  "email": "user@example.com",    // 邮箱地址
  "password": "password123",      // 密码6-128字符
  "verification_code": "123456",  // 邮箱验证码6位数字
  "avatar": "https://example.com/avatar.png" // 可选头像URL
}
  • 响应数据:
{
  "code": 200,
  "message": "注册成功",
  "data": {
    "token": "jwt_token_here",
    "user_info": {
      "id": 1,
      "username": "newuser",
      "email": "user@example.com",
      "avatar": "https://example.com/avatar.png",
      "points": 0,
      "role": "user",
      "status": 1,
      "created_at": "2025-10-01T10:00:00Z",
      "updated_at": "2025-10-01T10:00:00Z"
    }
  }
}

2. 用户登录

  • URL: POST /api/v1/auth/login
  • 认证: 无需认证
  • 请求参数:
{
  "username": "testuser",         // 用户名或邮箱
  "password": "password123"       // 密码
}
  • 响应数据:
{
  "code": 200,
  "message": "登录成功",
  "data": {
    "token": "jwt_token_here",
    "user_info": {
      "id": 1,
      "username": "testuser",
      "email": "test@example.com",
      "avatar": "https://example.com/avatar.png",
      "points": 100,
      "role": "user",
      "status": 1,
      "last_login_at": "2025-10-01T12:00:00Z",
      "created_at": "2025-10-01T10:00:00Z",
      "updated_at": "2025-10-01T10:00:00Z"
    }
  }
}

3. 发送验证码

  • URL: POST /api/v1/auth/send-code
  • 认证: 无需认证
  • 请求参数:
{
  "email": "user@example.com",    // 邮箱地址
  "type": "register"              // 类型: register/reset_password/change_email
}
  • 响应数据:
{
  "code": 200,
  "message": "验证码已发送,请查收邮件",
  "data": {
    "message": "验证码已发送,请查收邮件"
  }
}

4. 重置密码

  • URL: POST /api/v1/auth/reset-password
  • 认证: 无需认证
  • 请求参数:
{
  "email": "user@example.com",    // 邮箱地址
  "verification_code": "123456",  // 邮箱验证码
  "new_password": "newpassword123" // 新密码
}
  • 响应数据:
{
  "code": 200,
  "message": "密码重置成功",
  "data": {
    "message": "密码重置成功"
  }
}

用户相关 API

1. 获取用户信息

  • URL: GET /api/v1/user/profile
  • 认证: 需要JWT认证
  • 请求参数: 无
  • 响应数据:
{
  "code": 200,
  "message": "操作成功",
  "data": {
    "id": 1,
    "username": "testuser",
    "email": "test@example.com",
    "avatar": "https://example.com/avatar.png",
    "points": 100,
    "role": "user",
    "status": 1,
    "last_login_at": "2025-10-01T12:00:00Z",
    "created_at": "2025-10-01T10:00:00Z",
    "updated_at": "2025-10-01T10:00:00Z"
  }
}

2. 更新用户信息

  • URL: PUT /api/v1/user/profile
  • 认证: 需要JWT认证
  • 请求参数:
{
  "avatar": "https://example.com/new-avatar.png", // 可选新头像URL
  "old_password": "oldpassword123",              // 可选,修改密码时需要
  "new_password": "newpassword123"               // 可选,新密码
}
  • 响应数据:
{
  "code": 200,
  "message": "操作成功",
  "data": {
    "id": 1,
    "username": "testuser",
    "email": "test@example.com",
    "avatar": "https://example.com/new-avatar.png",
    "points": 100,
    "role": "user",
    "status": 1,
    "last_login_at": "2025-10-01T12:00:00Z",
    "created_at": "2025-10-01T10:00:00Z",
    "updated_at": "2025-10-01T10:00:00Z"
  }
}

3. 生成头像上传URL

  • URL: POST /api/v1/user/avatar/upload-url
  • 认证: 需要JWT认证
  • 请求参数:
{
  "file_name": "avatar.png"      // 文件名
}
  • 响应数据:
{
  "code": 200,
  "message": "操作成功",
  "data": {
    "post_url": "https://rustfs.example.com/avatars",
    "form_data": {
      "key": "user_1/xxx.png",
      "policy": "base64_policy",
      "x-amz-signature": "signature"
    },
    "avatar_url": "https://rustfs.example.com/avatars/user_1/xxx.png",
    "expires_in": 900
  }
}

4. 更新头像URL

  • URL: PUT /api/v1/user/avatar
  • 认证: 需要JWT认证
  • 请求参数:
    • Query参数: avatar_url - 头像URL
  • 响应数据:
{
  "code": 200,
  "message": "操作成功",
  "data": {
    "id": 1,
    "username": "testuser",
    "email": "test@example.com",
    "avatar": "https://example.com/new-avatar.png",
    "points": 100,
    "role": "user",
    "status": 1,
    "last_login_at": "2025-10-01T12:00:00Z",
    "created_at": "2025-10-01T10:00:00Z",
    "updated_at": "2025-10-01T10:00:00Z"
  }
}

5. 更换邮箱

  • URL: POST /api/v1/user/change-email
  • 认证: 需要JWT认证
  • 请求参数:
{
  "new_email": "newemail@example.com",  // 新邮箱地址
  "verification_code": "123456"         // 邮箱验证码
}
  • 响应数据:
{
  "code": 200,
  "message": "操作成功",
  "data": {
    "id": 1,
    "username": "testuser",
    "email": "newemail@example.com",
    "avatar": "https://example.com/avatar.png",
    "points": 100,
    "role": "user",
    "status": 1,
    "last_login_at": "2025-10-01T12:00:00Z",
    "created_at": "2025-10-01T10:00:00Z",
    "updated_at": "2025-10-01T10:00:00Z"
  }
}

6. 重置Yggdrasil密码

  • URL: POST /api/v1/user/yggdrasil-password/reset
  • 认证: 需要JWT认证
  • 请求参数: 无
  • 响应数据:
{
  "code": 200,
  "message": "操作成功",
  "data": {
    "password": "new_yggdrasil_password"
  }
}

材质相关 API

1. 搜索材质

  • URL: GET /api/v1/texture
  • 认证: 无需认证
  • 请求参数:
    • Query参数:
      • keyword: 搜索关键词
      • type: 材质类型 (SKIN/CAPE)
      • public_only: 是否只搜索公开材质 (true/false)
      • page: 页码默认1
      • page_size: 每页数量默认20
  • 响应数据:
{
  "code": 200,
  "message": "操作成功",
  "data": {
    "list": [
      {
        "id": 1,
        "uploader_id": 1,
        "name": "My Skin",
        "description": "A cool skin",
        "type": "SKIN",
        "url": "https://rustfs.example.com/textures/xxx.png",
        "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
        "size": 2048,
        "is_public": true,
        "download_count": 100,
        "favorite_count": 50,
        "is_slim": false,
        "status": 1,
        "created_at": "2025-10-01T10:00:00Z",
        "updated_at": "2025-10-01T10:00:00Z"
      }
    ],
    "total": 100,
    "page": 1,
    "page_size": 20,
    "total_pages": 5
  }
}

2. 获取材质详情

  • URL: GET /api/v1/texture/{id}
  • 认证: 无需认证
  • 请求参数:
    • 路径参数: id - 材质ID
  • 响应数据:
{
  "code": 200,
  "message": "操作成功",
  "data": {
    "id": 1,
    "uploader_id": 1,
    "name": "My Skin",
    "description": "A cool skin",
    "type": "SKIN",
    "url": "https://rustfs.example.com/textures/xxx.png",
    "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
    "size": 2048,
    "is_public": true,
    "download_count": 100,
    "favorite_count": 50,
    "is_slim": false,
    "status": 1,
    "created_at": "2025-10-01T10:00:00Z",
    "updated_at": "2025-10-01T10:00:00Z"
  }
}

3. 直接上传材质文件(推荐)

  • URL: POST /api/v1/texture/upload
  • 认证: 需要JWT认证
  • Content-Type: multipart/form-data
  • 请求参数:
    • file: 材质文件PNG格式1KB-10MB
    • name: 材质名称必填1-100字符
    • description: 材质描述可选最多500字符
    • type: 材质类型可选默认SKIN可选值SKIN/CAPE
    • is_public: 是否公开可选默认falsetrue/false
    • is_slim: 是否为细臂模型可选默认falsetrue/false
  • 说明:
    • 后端会自动计算文件的SHA256哈希值
    • 如果已存在相同哈希的材质会复用已存在的文件URL不重复上传
    • 允许多次上传相同哈希的材质(包括同一用户),每次都会创建新的数据库记录
    • 文件存储路径格式:{type}/{hash[:2]}/{hash[2:4]}/{hash}.png
  • 响应数据:
{
  "code": 200,
  "message": "操作成功",
  "data": {
    "id": 1,
    "uploader_id": 1,
    "name": "My Cool Skin",
    "description": "A very cool skin",
    "type": "SKIN",
    "url": "https://rustfs.example.com/textures/skin/e3/b0/e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.png",
    "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
    "size": 2048,
    "is_public": true,
    "download_count": 0,
    "favorite_count": 0,
    "is_slim": false,
    "status": 1,
    "created_at": "2025-10-01T10:00:00Z",
    "updated_at": "2025-10-01T10:00:00Z"
  }
}

4. 生成材质上传URL兼容接口

  • URL: POST /api/v1/texture/upload-url
  • 认证: 需要JWT认证
  • 请求参数:
{
  "file_name": "skin.png",        // 文件名
  "texture_type": "SKIN"          // 材质类型: SKIN/CAPE
}
  • 响应数据:
{
  "code": 200,
  "message": "操作成功",
  "data": {
    "post_url": "https://rustfs.example.com/textures",
    "form_data": {
      "key": "user_1/skin/xxx.png",
      "policy": "base64_policy",
      "x-amz-signature": "signature"
    },
    "texture_url": "https://rustfs.example.com/textures/user_1/skin/xxx.png",
    "expires_in": 900
  }
}

5. 创建材质记录配合预签名URL使用

  • URL: POST /api/v1/texture
  • 认证: 需要JWT认证
  • 请求参数:
{
  "name": "My Cool Skin",          // 材质名称1-100字符
  "description": "A very cool skin", // 描述最多500字符
  "type": "SKIN",                  // 材质类型: SKIN/CAPE
  "url": "https://rustfs.example.com/textures/user_1/skin/xxx.png", // 材质URL
  "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", // SHA256哈希
  "size": 2048,                    // 文件大小(字节)
  "is_public": true,               // 是否公开
  "is_slim": false                 // 是否为细臂模型(Alex)
}
  • 响应数据:
{
  "code": 200,
  "message": "操作成功",
  "data": {
    "id": 1,
    "uploader_id": 1,
    "name": "My Cool Skin",
    "description": "A very cool skin",
    "type": "SKIN",
    "url": "https://rustfs.example.com/textures/user_1/skin/xxx.png",
    "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
    "size": 2048,
    "is_public": true,
    "download_count": 0,
    "favorite_count": 0,
    "is_slim": false,
    "status": 1,
    "created_at": "2025-10-01T10:00:00Z",
    "updated_at": "2025-10-01T10:00:00Z"
  }
}

6. 更新材质

  • URL: PUT /api/v1/texture/{id}
  • 认证: 需要JWT认证
  • 请求参数:
    • 路径参数: id - 材质ID
    • 请求体:
{
  "name": "Updated Skin Name",     // 可选,新名称
  "description": "Updated description", // 可选,新描述
  "is_public": false              // 可选,是否公开
}
  • 响应数据:
{
  "code": 200,
  "message": "操作成功",
  "data": {
    "id": 1,
    "uploader_id": 1,
    "name": "Updated Skin Name",
    "description": "Updated description",
    "type": "SKIN",
    "url": "https://rustfs.example.com/textures/user_1/skin/xxx.png",
    "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
    "size": 2048,
    "is_public": false,
    "download_count": 100,
    "favorite_count": 50,
    "is_slim": false,
    "status": 1,
    "created_at": "2025-10-01T10:00:00Z",
    "updated_at": "2025-10-01T10:00:00Z"
  }
}

7. 删除材质

  • URL: DELETE /api/v1/texture/{id}
  • 认证: 需要JWT认证
  • 请求参数:
    • 路径参数: id - 材质ID
  • 响应数据:
{
  "code": 200,
  "message": "操作成功",
  "data": null
}

8. 切换收藏状态

  • URL: POST /api/v1/texture/{id}/favorite
  • 认证: 需要JWT认证
  • 请求参数:
    • 路径参数: id - 材质ID
  • 响应数据:
{
  "code": 200,
  "message": "操作成功",
  "data": {
    "is_favorited": true
  }
}

9. 获取用户上传的材质列表

  • URL: GET /api/v1/texture/my
  • 认证: 需要JWT认证
  • 请求参数:
    • Query参数:
      • page: 页码默认1
      • page_size: 每页数量默认20
  • 响应数据:
{
  "code": 200,
  "message": "操作成功",
  "data": {
    "list": [
      {
        "id": 1,
        "uploader_id": 1,
        "name": "My Skin",
        "description": "A cool skin",
        "type": "SKIN",
        "url": "https://rustfs.example.com/textures/xxx.png",
        "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
        "size": 2048,
        "is_public": true,
        "download_count": 100,
        "favorite_count": 50,
        "is_slim": false,
        "status": 1,
        "created_at": "2025-10-01T10:00:00Z",
        "updated_at": "2025-10-01T10:00:00Z"
      }
    ],
    "total": 50,
    "page": 1,
    "page_size": 20,
    "total_pages": 3
  }
}

10. 获取用户收藏的材质列表

  • URL: GET /api/v1/texture/favorites
  • 认证: 需要JWT认证
  • 请求参数:
    • Query参数:
      • page: 页码默认1
      • page_size: 每页数量默认20
  • 响应数据:
{
  "code": 200,
  "message": "操作成功",
  "data": {
    "list": [
      {
        "id": 1,
        "uploader_id": 2,
        "name": "Cool Skin",
        "description": "A very cool skin",
        "type": "SKIN",
        "url": "https://rustfs.example.com/textures/xxx.png",
        "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
        "size": 2048,
        "is_public": true,
        "download_count": 100,
        "favorite_count": 50,
        "is_slim": false,
        "status": 1,
        "created_at": "2025-10-01T10:00:00Z",
        "updated_at": "2025-10-01T10:00:00Z"
      }
    ],
    "total": 30,
    "page": 1,
    "page_size": 20,
    "total_pages": 2
  }
}

档案相关 API

1. 创建档案

  • URL: POST /api/v1/profile
  • 认证: 需要JWT认证
  • 请求参数:
{
  "name": "PlayerName"            // 角色名1-16字符
}
  • 响应数据:
{
  "code": 200,
  "message": "操作成功",
  "data": {
    "uuid": "550e8400-e29b-41d4-a716-446655440000",
    "user_id": 1,
    "name": "PlayerName",
    "skin_id": null,
    "cape_id": null,
    "is_active": false,
    "last_used_at": null,
    "created_at": "2025-10-01T10:00:00Z",
    "updated_at": "2025-10-01T10:00:00Z"
  }
}

2. 获取档案列表

  • URL: GET /api/v1/profile
  • 认证: 需要JWT认证
  • 请求参数: 无
  • 响应数据:
{
  "code": 200,
  "message": "操作成功",
  "data": [
    {
      "uuid": "550e8400-e29b-41d4-a716-446655440000",
      "user_id": 1,
      "name": "PlayerName",
      "skin_id": 1,
      "cape_id": 2,
      "is_active": true,
      "last_used_at": "2025-10-01T12:00:00Z",
      "created_at": "2025-10-01T10:00:00Z",
      "updated_at": "2025-10-01T10:00:00Z"
    }
  ]
}

3. 获取档案详情

  • URL: GET /api/v1/profile/{uuid}
  • 认证: 无需认证
  • 请求参数:
    • 路径参数: uuid - 档案UUID
  • 响应数据:
{
  "code": 200,
  "message": "操作成功",
  "data": {
    "uuid": "550e8400-e29b-41d4-a716-446655440000",
    "user_id": 1,
    "name": "PlayerName",
    "skin_id": 1,
    "cape_id": 2,
    "is_active": true,
    "last_used_at": "2025-10-01T12:00:00Z",
    "created_at": "2025-10-01T10:00:00Z",
    "updated_at": "2025-10-01T10:00:00Z"
  }
}

4. 更新档案

  • URL: PUT /api/v1/profile/{uuid}
  • 认证: 需要JWT认证
  • 请求参数:
    • 路径参数: uuid - 档案UUID
    • 请求体:
{
  "name": "NewPlayerName",        // 可选,新角色名
  "skin_id": 1,                   // 可选皮肤ID
  "cape_id": 2                    // 可选披风ID
}
  • 响应数据:
{
  "code": 200,
  "message": "操作成功",
  "data": {
    "uuid": "550e8400-e29b-41d4-a716-446655440000",
    "user_id": 1,
    "name": "NewPlayerName",
    "skin_id": 1,
    "cape_id": 2,
    "is_active": true,
    "last_used_at": "2025-10-01T12:00:00Z",
    "created_at": "2025-10-01T10:00:00Z",
    "updated_at": "2025-10-01T10:00:00Z"
  }
}

5. 删除档案

  • URL: DELETE /api/v1/profile/{uuid}
  • 认证: 需要JWT认证
  • 请求参数:
    • 路径参数: uuid - 档案UUID
  • 响应数据:
{
  "code": 200,
  "message": "操作成功",
  "data": {
    "message": "删除成功"
  }
}

6. 设置活跃档案

  • URL: POST /api/v1/profile/{uuid}/activate
  • 认证: 需要JWT认证
  • 请求参数:
    • 路径参数: uuid - 档案UUID
  • 响应数据:
{
  "code": 200,
  "message": "操作成功",
  "data": {
    "message": "设置成功"
  }
}

验证码相关 API

1. 生成验证码

  • URL: GET /api/v1/captcha/generate
  • 认证: 无需认证
  • 请求参数: 无
  • 响应数据:
{
  "code": 200,
  "data": {
    "masterImage": "base64_encoded_master_image",
    "tileImage": "base64_encoded_tile_image",
    "captchaId": "captcha_id_here",
    "y": 100
  }
}

2. 验证验证码

  • URL: POST /api/v1/captcha/verify
  • 认证: 无需认证
  • 请求参数:
{
  "captchaId": "captcha_id_here",
  "dx": 150                        // 滑动距离
}
  • 响应数据:
{
  "code": 200,
  "msg": "验证成功"
}

系统相关 API

1. 获取系统配置

  • URL: GET /api/v1/system/config
  • 认证: 无需认证
  • 请求参数: 无
  • 响应数据:
{
  "code": 200,
  "message": "操作成功",
  "data": {
    "site_name": "CarrotSkin",
    "site_description": "A Minecraft Skin Station",
    "registration_enabled": true,
    "max_textures_per_user": 100,
    "max_profiles_per_user": 5
  }
}

CustomSkin API

1. 获取玩家信息

  • URL: GET /api/v1/csl/{username}
  • 认证: 无需认证
  • 请求参数:
    • 路径参数: username - 玩家用户名
  • 响应数据:
{
  "username": "PlayerName",
  "textures": {
    "default": "skin_hash_here",
    "slim": "skin_hash_here",
    "cape": "cape_hash_here",
    "elytra": "cape_hash_here"
  }
}

或简化格式:

{
  "username": "PlayerName",
  "skin": "skin_hash_here"
}

2. 获取资源文件

  • URL: GET /api/v1/csl/textures/{hash}
  • 认证: 无需认证
  • 请求参数:
    • 路径参数: hash - 资源哈希值
  • 响应数据: 二进制文件内容

健康检查

1. 健康检查

  • URL: GET /health
  • 认证: 无需认证
  • 请求参数: 无
  • 响应数据:
{
  "status": "ok"
}

错误码说明

错误码 说明
200 操作成功
400 请求参数错误
401 未认证或认证失败
403 无权限操作
404 资源不存在
500 服务器内部错误

认证说明

需要JWT认证的API需要在请求头中添加

Authorization: Bearer {jwt_token}

JWT Token在用户登录或注册成功后返回有效期内可用于访问需要认证的API。