Files
PR-Helper/docs/05-api-reference.md
T

661 lines
9.0 KiB
Markdown
Raw Normal View History

# API 接口文档
## 概述
PR-Helper 提供 RESTful JSON API 和 SSE 流式端点。所有 API 都需要认证(除登录/注册外)。
## 认证
### 会话认证
- 基于 Cookie 的会话
- Cookie 名称: `pr_session`
- 有效期: 7 天
- HttpOnly: true
### 认证头
所有受保护的 API 需要有效的会话 Cookie。
## 公开端点
### 登录页面
```
GET /login
```
返回登录页面 HTML。
### 注册页面
```
GET /register
```
返回注册页面 HTML。
### 用户登录
```
POST /api/auth/login
Content-Type: application/json
{
"email": "user@example.com",
"password": "password123"
}
```
**响应**:
```json
{
"message": "登录成功"
}
```
**错误**:
```json
{
"error": "邮箱或密码错误"
}
```
### 用户注册
```
POST /api/auth/register
Content-Type: application/json
{
"email": "user@example.com",
"password": "password123"
}
```
**响应**:
```json
{
"message": "注册成功"
}
```
### 用户登出
```
POST /api/auth/logout
```
**响应**:
```json
{
"message": "已登出"
}
```
## 页面端点
### 首页
```
GET /
```
返回首页 HTML(仓库列表)。
### 仓库详情页
```
GET /repo/:id
```
返回仓库详情页 HTML(Git 图形、差异查看器等)。
### 设置页
```
GET /settings
```
返回设置页面 HTML。
## 仓库管理 API
### 获取仓库列表
```
GET /api/repos
```
**响应**:
```json
[
{
"id": 1,
"url": "https://github.com/user/repo.git",
"local_path": "data/repos/user_repo.git_1234567890",
"size_bytes": 1048576,
"cloned_at": "2024-01-01T00:00:00Z",
"last_used": "2024-01-01T12:00:00Z",
"auth_type": "none"
}
]
```
### 克隆仓库
```
POST /api/repos
Content-Type: application/json
{
"url": "https://github.com/user/repo.git",
"auth_type": "none",
"credential": ""
}
```
**认证类型**:
- `none`: 无认证
- `https`: HTTPS 基本认证(credential = "username:password")
**响应 (SSE 流)**:
```
event: progress
data: {"step":"开始克隆","current":0,"total":0}
event: progress
data: {"step":"克隆完成","current":1,"total":1}
event: done
data: {"repo_id":1,"branches":["main","dev"],"tags":["v1.0"],"commit_num":100}
```
### 删除仓库
```
DELETE /api/repos/:id
```
**响应**:
```json
{
"message": "仓库已删除"
}
```
### 清理仓库缓存
```
POST /api/repos/:id/cleanup
```
删除并重新克隆仓库。
**响应 (SSE 流)**:
```
event: progress
data: {"step":"清理完成"}
event: progress
data: {"step":"开始克隆"}
event: done
data: {"repo_id":1}
```
### 拉取更新
```
POST /api/repos/:id/pull
```
**响应 (SSE 流)**:
```
event: progress
data: {"step":"拉取完成"}
event: done
data: {"commit_num":105,"branches":["main","dev"]}
```
### 获取 Git 图形
```
GET /api/repos/:id/graph
```
**响应**:
```json
{
"commits": [
{
"hash": "abc123...",
"short_hash": "abc1234",
"message": "feat: add new feature",
"author": "John Doe",
"email": "john@example.com",
"timestamp": "2024-01-01T12:00:00Z",
"parent_ids": ["def456..."]
}
],
"refs": [
{
"name": "main",
"hash": "abc123...",
"is_head": true,
"is_tag": false
},
{
"name": "v1.0",
"hash": "abc123...",
"is_head": false,
"is_tag": true
}
],
"edges": [
{
"source": "abc123...",
"target": "def456..."
}
]
}
```
### 获取引用列表
```
GET /api/repos/:id/refs
```
**响应**:
```json
[
{
"name": "main",
"hash": "abc123...",
"is_head": true,
"is_tag": false
},
{
"name": "v1.0",
"hash": "abc123...",
"is_head": false,
"is_tag": true
}
]
```
### 获取提交列表
```
GET /api/repos/:id/commits?ref=main&limit=50
```
**参数**:
| 参数 | 类型 | 必需 | 说明 |
|------|------|------|------|
| ref | string | 否 | 分支/标签名(默认 HEAD) |
| limit | int | 否 | 最大提交数(默认 50) |
**响应**:
```json
[
{
"hash": "abc123...",
"short_hash": "abc1234",
"message": "feat: add new feature",
"author": "John Doe",
"email": "john@example.com",
"timestamp": "2024-01-01T12:00:00Z",
"parent_ids": ["def456..."]
}
]
```
### 获取差异
```
GET /api/repos/:id/diff?base=main&head=feature
```
**参数**:
| 参数 | 类型 | 必需 | 说明 |
|------|------|------|------|
| base | string | 是 | 基准分支/标签/提交 |
| head | string | 是 | 目标分支/标签/提交 |
| per_file | bool | 否 | 是否按文件返回 |
**响应 (统一差异)**:
```json
{
"diff": "diff --git a/main.go b/main.go\n..."
}
```
**响应 (按文件)**:
```json
[
{
"filename": "main.go",
"patch": "diff --git a/main.go b/main.go\n..."
}
]
```
## PR 生成 API
### 生成 PR 描述
```
POST /api/repos/:id/generate
Content-Type: application/json
{
"base": "main",
"head": "feature"
}
```
**响应 (SSE 流)**:
```
event: content
data: {"content":"# 标题\n\n"}
event: content
data: {"content":"**类型**: feat\n\n"}
event: content
data: {"content":"## 概述\n..."}
event: done
data: {"content":""}
```
## 代码审查 API
### 执行代码审查
```
POST /api/repos/:id/review
Content-Type: application/json
{
"base": "main",
"head": "feature",
"top_n": 20,
"concurrency": 5
}
```
**参数**:
| 参数 | 类型 | 必需 | 说明 |
|------|------|------|------|
| base | string | 是 | 基准分支 |
| head | string | 是 | 目标分支 |
| top_n | int | 否 | 审查文件数上限(默认 20) |
| concurrency | int | 否 | 并发数(默认 5) |
**响应 (SSE 流)**:
```
event: start
data: {"total_files":30,"reviewed_files":20,"top_n":20}
event: file_start
data: {"file":"main.go","index":1,"total":20}
event: content
data: {"content":"..."}
event: suggestion
data: {"file":"main.go","severity":"warning","content":"..."}
event: file_end
data: {"file":"main.go"}
event: summary
data: {"score":7,"overall":"...","findings":"...","recommendations":"..."}
event: analysis_saved
data: {"analysis_id":1}
event: done
data: {"content":""}
```
### 获取审查历史
```
GET /api/repos/:id/review/analyses
```
**响应**:
```json
[
{
"id": 1,
"base_ref": "main",
"head_ref": "feature",
"created_at": "2024-01-01T12:00:00Z"
}
]
```
### 获取单个审查结果
```
GET /api/repos/:id/review/analyses/:aid
```
**响应**:
```json
{
"id": 1,
"base_ref": "main",
"head_ref": "feature",
"created_at": "2024-01-01T12:00:00Z",
"result": {
"file_reviews": [...],
"summary": {...},
"top_n": 20
}
}
```
### 保存审查笔记
```
POST /api/repos/:id/review/notes
Content-Type: application/json
{
"analysis_id": 1,
"scope": "file",
"scope_key": "main.go",
"content": "这个文件需要重构"
}
```
**scope 类型**:
| scope | scope_key | 说明 |
|-------|-----------|------|
| overall | (空) | 整体笔记 |
| file | 文件名 | 文件级笔记 |
| suggestion | 建议 ID | 建议级笔记 |
**响应**:
```json
{
"id": 1,
"analysis_id": 1,
"scope": "file",
"scope_key": "main.go",
"content": "这个文件需要重构",
"created_at": "2024-01-01T12:00:00Z",
"updated_at": "2024-01-01T12:00:00Z"
}
```
### 获取审查笔记
```
GET /api/repos/:id/review/notes?analysis_id=1&scope=file
```
**参数**:
| 参数 | 类型 | 必需 | 说明 |
|------|------|------|------|
| analysis_id | int | 是 | 分析 ID |
| scope | string | 否 | 过滤作用域 |
**响应**:
```json
[
{
"id": 1,
"analysis_id": 1,
"scope": "file",
"scope_key": "main.go",
"content": "这个文件需要重构",
"created_at": "2024-01-01T12:00:00Z",
"updated_at": "2024-01-01T12:00:00Z"
}
]
```
## 设置 API
### 获取设置
```
GET /api/settings
```
**响应**:
```json
{
"llm.endpoint": "https://api.deepseek.com",
"llm.api_key": "sk-...",
"llm.model": "deepseek-v4-pro",
"review.top_n": "20",
"review.concurrency": "5",
"cache.max_age_days": "7",
"cache.max_size_mb": "5000"
}
```
### 更新设置
```
PUT /api/settings
Content-Type: application/json
{
"llm.endpoint": "https://api.openai.com",
"llm.api_key": "sk-...",
"llm.model": "gpt-4"
}
```
**响应**:
```json
{
"message": "设置已更新"
}
```
## 错误响应
### 格式
```json
{
"error": "错误信息"
}
```
### 常见状态码
| 状态码 | 说明 |
|--------|------|
| 200 | 成功 |
| 400 | 请求参数错误 |
| 401 | 未认证 |
| 404 | 资源不存在 |
| 500 | 服务器内部错误 |
## SSE 协议
### 事件格式
```
event: {event_name}
data: {json_data}
```
- 每个事件以 `event:` 开头
- 数据以 `data:` 开头
- 事件之间用空行分隔
- 数据必须是有效的 JSON
### 客户端实现
```javascript
SSE.post(url, body, {
eventName: (data) => {
// 处理事件
},
error: (data) => {
// 处理错误
},
done: () => {
// 流结束
}
});
```
### 中断请求
```javascript
const controller = SSE.post(url, body, handlers);
// 中断
controller.abort();
```
## 限流
当前无速率限制。建议在反向代理层实现限流。
## CORS
当前不支持跨域请求。仅限同源访问。