275e5cc886
- 01-architecture.md: 架构概览 - 02-backend-services.md: 后端服务层 - 03-frontend-interaction.md: 前端交互设计 - 04-database-design.md: 数据库设计 - 05-api-reference.md: API 接口文档 - 06-sse-streaming.md: SSE 流式传输 - 07-llm-integration.md: LLM 集成 - 08-deployment.md: 部署运维 - 09-development-guide.md: 开发指南 - 10-troubleshooting.md: 故障排查
661 lines
9.0 KiB
Markdown
661 lines
9.0 KiB
Markdown
# 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
|
||
|
||
当前不支持跨域请求。仅限同源访问。
|