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.8 KiB
5.8 KiB
Folder API 查询参数格式修复
日期: 2026-01-29
类型: Bug 修复
影响范围: 前端 Folder API 服务
问题描述
前端调用 Folder API 时,查询参数使用了 snake_case 格式(如 folder_category),但后端 API 规范要求使用 camelCase 格式(如 folderCategory),导致请求失败。
错误示例:
GET /api/v1/folders?folder_category=1 ❌
错误响应:
{
"success": false,
"code": 400,
"message": "查询根文件夹时必须指定 folder_category",
"data": null
}
根本原因
client/src/services/api/folders.ts 中的 API 调用使用了 keysToSnakeCase() 工具函数转换查询参数,将 camelCase 参数名转换为 snake_case,与后端 API 规范不符。
解决方案
修改文件
client/src/services/api/folders.ts
具体变更
1. getAll() 方法
修改前:
async getAll(params?: {
parentId?: string | null;
folderCategory?: FolderCategory;
page?: number;
pageSize?: number;
}): Promise<FolderListResponse> {
const queryParams = keysToSnakeCase(params || {}); // ❌ 转换为 snake_case
const response = await apiClient.get<FolderListResponse>('/folders', {
params: queryParams,
});
return keysToCamelCase(response);
}
修改后:
async getAll(params?: {
parentId?: string | null;
folderCategory?: FolderCategory;
page?: number;
pageSize?: number;
}): Promise<FolderListResponse> {
// 查询参数保持 camelCase,符合 API 规范
const response = await apiClient.get<FolderListResponse>('/folders', {
params: params, // ✅ 保持 camelCase
});
return keysToCamelCase(response);
}
2. getTree() 方法
修改前:
async getTree(params?: {
maxDepth?: number;
includeProjects?: boolean;
}): Promise<{ tree: FolderTreeNode[] }> {
const queryParams: Record<string, any> = {};
if (params?.maxDepth) queryParams.max_depth = params.maxDepth; // ❌ snake_case
if (params?.includeProjects) queryParams.include_projects = params.includeProjects; // ❌ snake_case
const response = await apiClient.get<{ tree: FolderTreeNode[] }>('/folders/tree', {
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
});
return keysToCamelCase(response);
}
修改后:
async getTree(params?: {
maxDepth?: number;
includeProjects?: boolean;
}): Promise<{ tree: FolderTreeNode[] }> {
// 查询参数保持 camelCase,符合 API 规范
const response = await apiClient.get<{ tree: FolderTreeNode[] }>('/folders/tree', {
params: params, // ✅ 保持 camelCase
});
return keysToCamelCase(response);
}
3. getById() 方法
修改前:
async getById(id: string, includeBreadcrumbs = true): Promise<Folder> {
const response = await apiClient.get<Folder>(`/folders/${id}`, {
params: { include_breadcrumbs: includeBreadcrumbs }, // ❌ snake_case
});
return keysToCamelCase(response);
}
修改后:
async getById(id: string, includeBreadcrumbs = true): Promise<Folder> {
const response = await apiClient.get<Folder>(`/folders/${id}`, {
params: { includeBreadcrumbs }, // ✅ camelCase
});
return keysToCamelCase(response);
}
API 规范说明
根据 docs/requirements/api-design-specification.md 和 .claude/skills/jointo-tech-stack/references/api-design.md:
查询参数命名规范
参数命名使用 camelCase:
folderIdpageSizesortBysortOrderfolderCategoryparentId
正确的 API 调用示例
GET /api/v1/folders?folderCategory=1&parentId=null&page=1&pageSize=20
GET /api/v1/folders/tree?maxDepth=3&includeProjects=true
GET /api/v1/folders/{id}?includeBreadcrumbs=true
影响范围
修复的功能
✅ 获取文件夹列表(根文件夹和子文件夹)
✅ 获取文件夹树形结构
✅ 获取文件夹详情(包含面包屑)
不受影响的功能
- 创建文件夹(POST 请求体使用 snake_case,符合后端 Pydantic 模型)
- 更新文件夹(PUT 请求体使用 snake_case,符合后端 Pydantic 模型)
- 删除文件夹
- 移动文件夹
测试验证
手动测试
# 1. 获取根文件夹列表(我的项目)
curl -X GET "http://localhost:6160/api/v1/folders?folderCategory=1" \
-H "Authorization: Bearer <token>"
# 2. 获取文件夹树
curl -X GET "http://localhost:6160/api/v1/folders/tree?maxDepth=3&includeProjects=true" \
-H "Authorization: Bearer <token>"
# 3. 获取文件夹详情
curl -X GET "http://localhost:6160/api/v1/folders/{id}?includeBreadcrumbs=true" \
-H "Authorization: Bearer <token>"
预期结果
所有请求应返回 200 OK 和正确的数据,不再出现 400 Bad Request 错误。
相关文档
- API 设计规范:
docs/requirements/api-design-specification.md - Jointo Tech Stack Skill:
.claude/skills/jointo-tech-stack/references/api-design.md - 后端 Folder API:
server/app/api/v1/folders.py
经验教训
-
查询参数 vs 请求体:
- 查询参数(GET):使用 camelCase,直接传递,不转换
- 请求体(POST/PUT):使用 snake_case,需要
keysToSnakeCase()转换
-
API 规范一致性:
- 前后端必须遵循统一的命名规范
- 查询参数应与后端 FastAPI 的
alias参数保持一致
-
工具函数使用场景:
keysToSnakeCase():仅用于 POST/PUT 请求体keysToCamelCase():用于所有响应数据- 查询参数:保持原始 camelCase 格式
后续优化建议
- 在
api-utils.ts中添加注释,明确说明各工具函数的使用场景 - 考虑创建专门的查询参数类型,确保类型安全
- 添加单元测试验证查询参数格式