211 lines
8.4 KiB
Markdown
211 lines
8.4 KiB
Markdown
# TraceStudio — 后端 API 文档(server 视角)
|
||
|
||
本文件以实现代码为准,汇总了当前后端提供的 HTTP API(可用于生成 OpenAPI 或 mock server)。所有路径以服务器根地址为前缀,路由通常被挂载在 `/api` 下(例如最终完整路径为 `/api/files/list`)。
|
||
|
||
**概览**
|
||
- **Backend stack**: FastAPI(Python 3.11+)、Polars、自定义节点加载/执行框架。
|
||
- **安全约定**: 所有文件路径会经过 `sanitize_path` / `is_safe_path` 校验以防目录遍历;自定义节点文件名通过 `NodeValidator.is_safe_filename` 验证。
|
||
|
||
**DataFrame 序列化说明**
|
||
- **字段约定**: 后端在返回计算结果中会将 `polars.DataFrame` 序列化为一个带 `__type: DataFrame` 的对象以便前端预览与分页请求。
|
||
- **结构示例**:
|
||
|
||
```json
|
||
{
|
||
"__type": "DataFrame",
|
||
"columns": ["col1", "col2"],
|
||
"preview": [{"col1": 1, "col2": "a"}, ...],
|
||
"rows": 1234
|
||
}
|
||
```
|
||
|
||
此格式用于 `/node/preview` 返回和 `/graph/execute` 中每个节点 outputs 的预览。`preview` 的长度受服务端限制(通常为 10 或 20)。
|
||
|
||
**全局错误处理约定**
|
||
- 成功返回一般为 JSON 对象并包含 `success` 或 `status: "success"`。
|
||
- 失败时使用 HTTP 错误码(400/403/404/500)并在 body 中提供 `detail` 字段;`/graph/execute` 在 500 时会返回更详细的 `traceback` 对象。
|
||
|
||
--
|
||
|
||
**1) 文件与文件管理(Files)**
|
||
|
||
说明: 文件相关接口分布在 `server/file_manager.py`(router prefix `/api/files`)与 `server/app/api/endpoints_upload.py`(被挂载到 `/api`,内部路径为 `/files/*`),两套接口在功能上有重叠,前端可以任选其一,推荐使用 `/api/files/*` 族。
|
||
|
||
- `GET /api/files/list` — 列出目录
|
||
- Query: `path`(string, 可空,空或 `/` 表示根),`username`(可选,用于确保用户目录存在)
|
||
- Response: `{ "path": "...", "items": [ {name,path,type,size,modified,extension}, ... ] }
|
||
- Errors: 400(路径不是目录)、403(路径非法)、404(路径不存在)、500(读取失败)
|
||
|
||
- `POST /api/files/upload` — 上传文件(multipart)
|
||
- Form: `file` (multipart file)
|
||
- Query: `path`(目标目录)、`username`(可选)
|
||
- Response: `{ "success": true, "file": FileInfo, "message": "..." }`
|
||
- Notes: 如果同名文件已存在会自动加后缀避免覆盖(除非使用专门的 save/force 接口)。
|
||
|
||
- `POST /api/files/action` — 文件基本操作
|
||
- Body: `FileAction` 模型 `{ action, path, target?, new_name? }`
|
||
- 支持操作: `move`, `delete`, `mkdir`, `rename`
|
||
- Response: 视操作返回 `{ success: true, ... }` 或详细信息
|
||
|
||
- `GET /api/files/download` — 下载
|
||
- Query: `path`(必需)
|
||
- Response: 返回 `FileResponse` (streamed)
|
||
|
||
- `GET /api/files/info` — 获取文件/文件夹信息
|
||
- Query: `path`(必需)
|
||
- Response: `FileInfo`(或 `{ exists: false }`)
|
||
|
||
模型参考 (`FileInfo`, `FileAction`)
|
||
|
||
```py
|
||
class FileInfo(BaseModel):
|
||
name: str
|
||
path: str
|
||
type: str # 'file' | 'folder'
|
||
size: Optional[int]
|
||
modified: Optional[str]
|
||
extension: Optional[str]
|
||
|
||
class FileAction(BaseModel):
|
||
action: str # 'move'|'delete'|'mkdir'|'rename'
|
||
path: str
|
||
target: Optional[str]
|
||
new_name: Optional[str]
|
||
```
|
||
|
||
实现状态: 已实现(路径清理、权限检查、用户目录创建、重命名/删除/移动、下载流)。
|
||
|
||
--
|
||
|
||
**2) 图/节点(Graph & Node)**
|
||
|
||
- `GET /api/plugins` — 获取可用节点插件
|
||
- Response: `{ "plugins": { class_name: metadata }, "total": N, "categories": [...] }`
|
||
- Notes: metadata 包含 `display_name`, `category`, `description`, `inputs`, `outputs`, `param_schema`, `class_name` 等。
|
||
|
||
- `POST /api/node/preview` — 预览单个节点执行结果
|
||
- Body: `NodePreviewRequest` `{ node: NodeSchema, limit: int = 10 }`
|
||
- NodeSchema 支持 `data` 或 `params` 两种字段(兼容历史 payload)
|
||
- Response 示例:
|
||
|
||
```json
|
||
{
|
||
"class_name": "MyNode",
|
||
"status": "success",
|
||
"columns": ["a","b"],
|
||
"preview": [{"a":1,"b":2}],
|
||
"context": {...}
|
||
}
|
||
```
|
||
|
||
- `POST /api/graph/execute` — 执行完整图
|
||
- Body: `GraphExecuteRequest` `{ nodes: [NodeSchema], edges: [EdgeSchema], settings?: {} }`
|
||
- Response (成功示例):
|
||
|
||
```json
|
||
{
|
||
"status": "success",
|
||
"message": "成功执行 3 个节点",
|
||
"execution_time": 0.123,
|
||
"results": {
|
||
"node1": { "status": "ok", "outputs": {"out": {"__type":"DataFrame", ...}}, "error": null }
|
||
},
|
||
"stats": { "total_nodes": 3, "total_edges": 2, "execution_order": ["node1","node2"] }
|
||
}
|
||
```
|
||
|
||
- 返回格式说明: `results` 为 node_id 映射;每个节点包含 `status`, `outputs`, `error`。如果输出为 DataFrame,按上文序列化规则返回。
|
||
|
||
模型摘要 (`NodeSchema`, `EdgeSchema`, `GraphExecuteRequest`)
|
||
|
||
```py
|
||
class NodeSchema(BaseModel):
|
||
id: str
|
||
type: str
|
||
class_name: Optional[str]
|
||
function: Optional[str]
|
||
data: Optional[Dict[str,Any]]
|
||
params: Optional[Dict[str,Any]]
|
||
|
||
class EdgeSchema(BaseModel):
|
||
id: Optional[str]
|
||
source: str
|
||
target: str
|
||
dimension_mode: str
|
||
source_port: Optional[str]
|
||
target_port: Optional[str]
|
||
|
||
class GraphExecuteRequest(BaseModel):
|
||
nodes: List[NodeSchema]
|
||
edges: List[EdgeSchema]
|
||
settings: Optional[Dict[str,Any]]
|
||
```
|
||
|
||
实现状态: 已实现。注意:后端兼容旧/新 executor 返回格式(可能是 `node_infos/node_results` 或 node_id->info 映射)。`/nodes/save` 接口为占位,尚需实现持久化策略。
|
||
|
||
--
|
||
|
||
**3) 自定义节点管理(Custom Nodes)**
|
||
|
||
- 前缀: `/api/custom-nodes/*`
|
||
|
||
- `GET /api/custom-nodes/list` — 列出自定义节点文件(含验证状态)
|
||
|
||
- `POST /api/custom-nodes/validate` — 验证节点代码(不保存)
|
||
- Body: `{ code: str, filename?: str }`
|
||
- Response: `{ success: true, validation: { valid: bool, errors: [...] } }`
|
||
|
||
- `GET /api/custom-nodes/read/{filename}` — 读取节点源码
|
||
- Response: `{ success: true, filename, code, size, modified }`
|
||
|
||
- `POST /api/custom-nodes/save` — 保存并加载节点
|
||
- Body: `{ filename, code, force?: bool }`
|
||
- 行为: 验证代码后保存,支持备份与强制覆盖,保存后调用 loader 加载节点并返回 `load_result`。
|
||
|
||
- `POST /api/custom-nodes/action` — 对节点执行 `load`/`unload`/`delete`/`rename`
|
||
|
||
- `GET /api/custom-nodes/download/{filename}` — 下载节点文件
|
||
|
||
- `POST /api/custom-nodes/upload` — 上传节点文件(会验证并加载)
|
||
|
||
- `GET /api/custom-nodes/loaded` — 返回运行时已加载类及其 metadata
|
||
|
||
- `POST /api/custom-nodes/reload-all` — 重新加载所有自定义节点
|
||
|
||
- `GET /api/custom-nodes/example` — 返回示例节点代码(供编辑器使用)
|
||
|
||
模型参考 (`NodeValidateRequest`, `NodeSaveRequest`, `NodeActionRequest`)
|
||
|
||
实现状态: 功能齐全(验证、保存、备份、加载/卸载、列出、下载)。注意:保存/上传过程会在保存前使用 `validate_node_code` 做静态验证并在失败时阻止加载。
|
||
|
||
--
|
||
|
||
**4) 用户管理相关(简要)**
|
||
|
||
- `GET /api/users/list` — 返回 `{ users: [...], count: N }`
|
||
- `POST /api/users/add` — 接受 `{ username, display_name? }`,会验证用户名格式、写入 users DB 并创建用户工作区。
|
||
|
||
实现状态: 已实现(基础用户 CRUD 含创建与列表)。
|
||
|
||
--
|
||
|
||
**5) 其他/占位接口**
|
||
|
||
- `POST /api/nodes/save` — 当前仅作占位,返回 success: true;需要后续实现节点保存到文件或 DB 的策略。
|
||
|
||
--
|
||
|
||
**对前端/集成测试的建议**
|
||
- 使用 `NodeSchema` 中的 `class_name` 作为后端加载的实现类标识;如果客户端只提供 `data/params` 中的 `meta.class_name`,后端也会兼容读取。
|
||
- 推荐按 `__type: DataFrame` 约定解析节点输出并在前端提供 DataFrame 视图组件(columns + preview + rows)。
|
||
- 自定义节点上传必须在后端验证通过后才加载,前端应展示 `validation` 结果并要求用户确认覆盖。
|
||
|
||
--
|
||
|
||
如需我把上述模型转换为可直接导入的 OpenAPI spec(`openapi.json`)以便一键生成 mock server 或 SDK,请回复确认,我会在下一步生成并附上简化 schema 片段。
|
||
|
||
---
|
||
|
||
引用实现: [server/file_manager.py](server/file_manager.py#L1-L400)
|
||
参考实现: [server/app/api/endpoints_upload.py](server/app/api/endpoints_upload.py#L1-L400), [server/app/api/endpoints_graph.py](server/app/api/endpoints_graph.py#L1-L400), [server/app/api/endpoints_custom_nodes.py](server/app/api/endpoints_custom_nodes.py#L1-L400)
|