You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

5.3 KiB

Folder Tree API 响应格式修复

日期: 2026-02-12
类型: Bug 修复
影响范围: Folder API
优先级: 高

问题描述

GET /api/v1/folders/tree 端点返回的项目节点缺少 FolderTreeNode schema 要求的必需字段,导致 FastAPI 响应验证失败。

错误日志

fastapi.exceptions.ResponseValidationError: 12 validation errors:
{'type': 'missing', 'loc': ('response', 'data', 'tree', 0, 'color'), 'msg': 'Field required'}
{'type': 'missing', 'loc': ('response', 'data', 'tree', 0, 'icon'), 'msg': 'Field required'}
{'type': 'missing', 'loc': ('response', 'data', 'tree', 0, 'level'), 'msg': 'Field required'}
{'type': 'missing', 'loc': ('response', 'data', 'tree', 0, 'projectCount'), 'msg': 'Field required'}
{'type': 'missing', 'loc': ('response', 'data', 'tree', 0, 'subfolderCount'), 'msg': 'Field required'}
...

根本原因

FolderTreeNode schema 定义的是文件夹节点结构,但树中混合了文件夹和项目节点,项目节点未提供这些必需字段:

  • description (Optional 但需显式提供)
  • color (Optional)
  • icon (Optional)
  • level (int, 必需)
  • projectCount (int, 必需)
  • subfolderCount (int, 必需)

解决方案

修复 1:修改 Schema 定义

修改文件: server/app/schemas/folder.py

FolderTreeResponse 改为匹配实际返回的根节点格式:

# 修改前
class FolderTreeResponse(BaseModel):
    """文件夹树响应"""
    tree: List[FolderTreeNode]

# 修改后
class FolderTreeResponse(BaseModel):
    """文件夹树响应(根节点格式)"""
    id: str
    name: str
    children: List[FolderTreeNode]

修复 2:为项目节点补充必需字段

修改文件:

  • server/app/services/folder_service.py
  • server/app/repositories/folder_repository.py

为项目节点和子项目节点添加 FolderTreeNode schema 要求的所有必需字段:

# 根项目节点
project_node = {
    "id": str(project.id),
    "name": project.name,
    "description": project.description,  # 新增
    "color": None,  # 新增(项目无颜色)
    "icon": None,  # 新增(项目无图标)
    "level": 0,  # 新增(根项目层级为 0)
    "type": "project",
    "folderCategory": project_folder_category,
    "projectCount": 0,  # 新增(项目不统计子项目)
    "subfolderCount": 0,  # 新增(项目无子文件夹)
    "isSubproject": False,
    "parentProjectId": None,
    "screenplayId": None,
    "children": []
}

# 子项目节点
subproject_node = {
    "id": str(subproject.id),
    "name": subproject.name,
    "description": subproject.description,  # 新增
    "color": None,  # 新增
    "icon": None,  # 新增
    "level": 1,  # 新增(子项目层级为 1)
    "type": "subproject",
    "folderCategory": project_folder_category,  # 新增
    "projectCount": 0,  # 新增
    "subfolderCount": 0,  # 新增
    "isSubproject": True,
    "parentProjectId": str(subproject.parent_project_id),
    "screenplayId": str(subproject.screenplay_id) if subproject.screenplay_id else None,
    "children": []
}

设计决策

为什么保持根节点格式?

前端代码已经有转换逻辑:

// client/src/services/api/folders.ts
const response = await apiClient.get<{ id: string; name: string; children: FolderTreeNode[] }>('/folders/tree', ...);
return { tree: data.children || [] };

前端期望后端返回 { id: "root", name: "根目录", children: [...] } 格式,然后自行转换为 { tree: [...] }。因此保持后端原有格式,仅修复项目节点缺失字段问题。

测试验证

验证步骤

  1. 重启 FastAPI 应用
  2. 调用 GET /api/v1/folders/tree?includeProjects=true&includeSubprojects=true 端点
  3. 确认响应格式为:
    {
      "code": 200,
      "message": "success",
      "data": {
        "id": "root",
        "name": "根目录",
        "children": [
          {
            "id": "...",
            "name": "...",
            "description": null,
            "color": null,
            "icon": null,
            "level": 0,
            "folderCategory": 1,
            "projectCount": 0,
            "subfolderCount": 0,
            "type": "project",
            "children": [...]
          }
        ]
      }
    }
    

预期结果

  • 响应验证通过,无 ResponseValidationError
  • 项目节点包含所有必需字段
  • 子项目节点包含所有必需字段
  • 前端可正常解析并展示树形结构

相关文件

  • server/app/schemas/folder.py - Schema 定义修改
  • server/app/services/folder_service.py - Service 层项目节点字段补充
  • server/app/repositories/folder_repository.py - Repository 层项目节点字段补充
  • server/app/api/v1/folders.py - API 端点(未修改)

影响评估

  • 前端影响: 无,前端已有兼容逻辑处理根节点格式
  • 向后兼容: 完全兼容,保持原有响应格式
  • 其他 API: 无影响,仅涉及 /folders/tree 端点

后续建议

  1. 添加集成测试覆盖该端点的响应格式验证
  2. 考虑重构 Schema 使用 Union[FolderTreeNode, ProjectTreeNode] 实现类型安全
  3. 在 API 文档中明确说明响应结构和项目节点的特殊字段

参考

  • ADR: docs/architecture/adrs/001-api-response-format-standardization.md
  • Schema 定义: server/app/schemas/folder.py:108-112