TraceStudio-dev/docs/server/api.md

211 lines
8.4 KiB
Markdown
Raw Normal View History

2026-01-10 19:08:49 +08:00
# 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)