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
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.pyserver/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: [...] }。因此保持后端原有格式,仅修复项目节点缺失字段问题。
测试验证
验证步骤
- 重启 FastAPI 应用
- 调用
GET /api/v1/folders/tree?includeProjects=true&includeSubprojects=true端点 - 确认响应格式为:
{ "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端点
后续建议
- 添加集成测试覆盖该端点的响应格式验证
- 考虑重构 Schema 使用
Union[FolderTreeNode, ProjectTreeNode]实现类型安全 - 在 API 文档中明确说明响应结构和项目节点的特殊字段
参考
- ADR:
docs/architecture/adrs/001-api-response-format-standardization.md - Schema 定义:
server/app/schemas/folder.py:108-112