# 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` 改为匹配实际返回的根节点格式: ```python # 修改前 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 要求的所有必需字段: ```python # 根项目节点 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": [] } ``` ### 设计决策 **为什么保持根节点格式?** 前端代码已经有转换逻辑: ```typescript // 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. 确认响应格式为: ```json { "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`