TraceStudio-dev/docs/server/api.md
Boshuang Zhao 5790ec164f add web v2
2026-01-10 19:08:49 +08:00

211 lines
8.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# TraceStudio — 后端 API 文档server 视角)
本文件以实现代码为准,汇总了当前后端提供的 HTTP API可用于生成 OpenAPI 或 mock server。所有路径以服务器根地址为前缀路由通常被挂载在 `/api` 下(例如最终完整路径为 `/api/files/list`)。
**概览**
- **Backend stack**: FastAPIPython 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)