579 lines
8.8 KiB
Markdown
579 lines
8.8 KiB
Markdown
# DramaLing API 端點文檔
|
||
|
||
## API 概述
|
||
|
||
Base URL:
|
||
- 開發環境: `http://localhost:3000/api`
|
||
- 生產環境: `https://dramaling.com/api`
|
||
|
||
認證方式: Bearer Token (Supabase JWT)
|
||
|
||
## 認證相關 API
|
||
|
||
### 註冊
|
||
```http
|
||
POST /api/auth/register
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"email": "user@example.com",
|
||
"password": "password123",
|
||
"username": "johndoe"
|
||
}
|
||
|
||
Response 200:
|
||
{
|
||
"user": {
|
||
"id": "uuid",
|
||
"email": "user@example.com",
|
||
"username": "johndoe"
|
||
},
|
||
"session": {
|
||
"access_token": "jwt_token",
|
||
"refresh_token": "refresh_token"
|
||
}
|
||
}
|
||
|
||
Response 400:
|
||
{
|
||
"error": "Email already registered"
|
||
}
|
||
```
|
||
|
||
### 登入
|
||
```http
|
||
POST /api/auth/login
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"email": "user@example.com",
|
||
"password": "password123"
|
||
}
|
||
|
||
Response 200:
|
||
{
|
||
"user": {
|
||
"id": "uuid",
|
||
"email": "user@example.com"
|
||
},
|
||
"session": {
|
||
"access_token": "jwt_token",
|
||
"refresh_token": "refresh_token"
|
||
}
|
||
}
|
||
|
||
Response 401:
|
||
{
|
||
"error": "Invalid credentials"
|
||
}
|
||
```
|
||
|
||
### 登出
|
||
```http
|
||
POST /api/auth/logout
|
||
Authorization: Bearer <token>
|
||
|
||
Response 200:
|
||
{
|
||
"message": "Logged out successfully"
|
||
}
|
||
```
|
||
|
||
### 取得當前用戶
|
||
```http
|
||
GET /api/auth/me
|
||
Authorization: Bearer <token>
|
||
|
||
Response 200:
|
||
{
|
||
"user": {
|
||
"id": "uuid",
|
||
"email": "user@example.com",
|
||
"username": "johndoe",
|
||
"created_at": "2024-01-01T00:00:00Z"
|
||
}
|
||
}
|
||
|
||
Response 401:
|
||
{
|
||
"error": "Unauthorized"
|
||
}
|
||
```
|
||
|
||
## 詞卡管理 API
|
||
|
||
### 取得詞卡列表
|
||
```http
|
||
GET /api/flashcards?page=1&limit=20&tag=business&search=hello
|
||
Authorization: Bearer <token>
|
||
|
||
Query Parameters:
|
||
- page: 頁碼 (預設: 1)
|
||
- limit: 每頁數量 (預設: 20, 最大: 100)
|
||
- tag: 標籤篩選
|
||
- search: 搜尋關鍵字
|
||
- sort: 排序方式 (created_at, difficulty, next_review_date)
|
||
- order: 排序順序 (asc, desc)
|
||
|
||
Response 200:
|
||
{
|
||
"flashcards": [
|
||
{
|
||
"id": "uuid",
|
||
"word": "Hello",
|
||
"translation": "你好",
|
||
"context": "Greeting",
|
||
"example": "Hello, how are you?",
|
||
"pronunciation": "/həˈloʊ/",
|
||
"difficulty": 1,
|
||
"next_review_date": "2024-01-02",
|
||
"tags": ["greeting", "basic"],
|
||
"created_at": "2024-01-01T00:00:00Z"
|
||
}
|
||
],
|
||
"pagination": {
|
||
"total": 100,
|
||
"page": 1,
|
||
"limit": 20,
|
||
"total_pages": 5
|
||
}
|
||
}
|
||
```
|
||
|
||
### 取得單一詞卡
|
||
```http
|
||
GET /api/flashcards/:id
|
||
Authorization: Bearer <token>
|
||
|
||
Response 200:
|
||
{
|
||
"flashcard": {
|
||
"id": "uuid",
|
||
"word": "Hello",
|
||
"translation": "你好",
|
||
"context": "Greeting",
|
||
"example": "Hello, how are you?",
|
||
"pronunciation": "/həˈloʊ/",
|
||
"difficulty": 1,
|
||
"next_review_date": "2024-01-02",
|
||
"review_count": 5,
|
||
"ease_factor": 2.5,
|
||
"interval": 1,
|
||
"tags": ["greeting", "basic"],
|
||
"created_at": "2024-01-01T00:00:00Z",
|
||
"updated_at": "2024-01-01T00:00:00Z"
|
||
}
|
||
}
|
||
|
||
Response 404:
|
||
{
|
||
"error": "Flashcard not found"
|
||
}
|
||
```
|
||
|
||
### 建立詞卡
|
||
```http
|
||
POST /api/flashcards
|
||
Authorization: Bearer <token>
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"word": "Hello",
|
||
"translation": "你好",
|
||
"context": "Greeting",
|
||
"example": "Hello, how are you?",
|
||
"pronunciation": "/həˈloʊ/",
|
||
"difficulty": 1,
|
||
"tags": ["greeting", "basic"]
|
||
}
|
||
|
||
Response 201:
|
||
{
|
||
"flashcard": {
|
||
"id": "uuid",
|
||
"word": "Hello",
|
||
...
|
||
}
|
||
}
|
||
|
||
Response 400:
|
||
{
|
||
"error": "Invalid flashcard data"
|
||
}
|
||
```
|
||
|
||
### 更新詞卡
|
||
```http
|
||
PUT /api/flashcards/:id
|
||
Authorization: Bearer <token>
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"translation": "您好",
|
||
"difficulty": 2,
|
||
"tags": ["greeting", "formal"]
|
||
}
|
||
|
||
Response 200:
|
||
{
|
||
"flashcard": {
|
||
"id": "uuid",
|
||
"word": "Hello",
|
||
"translation": "您好",
|
||
...
|
||
}
|
||
}
|
||
```
|
||
|
||
### 刪除詞卡
|
||
```http
|
||
DELETE /api/flashcards/:id
|
||
Authorization: Bearer <token>
|
||
|
||
Response 204: No Content
|
||
|
||
Response 404:
|
||
{
|
||
"error": "Flashcard not found"
|
||
}
|
||
```
|
||
|
||
### 批量操作
|
||
```http
|
||
POST /api/flashcards/batch
|
||
Authorization: Bearer <token>
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"action": "delete", // delete, update, add_tag, remove_tag
|
||
"ids": ["uuid1", "uuid2", "uuid3"],
|
||
"data": {
|
||
// 僅 update 和 tag 操作需要
|
||
"tags": ["new-tag"]
|
||
}
|
||
}
|
||
|
||
Response 200:
|
||
{
|
||
"success": true,
|
||
"affected": 3
|
||
}
|
||
```
|
||
|
||
## AI 生成 API
|
||
|
||
### 生成詞卡
|
||
```http
|
||
POST /api/ai/generate-flashcard
|
||
Authorization: Bearer <token>
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"text": "I'm gonna grab a coffee, wanna come?",
|
||
"type": "dialogue", // dialogue, topic, grammar
|
||
"count": 5,
|
||
"difficulty_range": [1, 3]
|
||
}
|
||
|
||
Response 200:
|
||
{
|
||
"flashcards": [
|
||
{
|
||
"word": "gonna",
|
||
"translation": "將要(going to 的口語形式)",
|
||
"context": "非正式對話",
|
||
"example": "I'm gonna grab a coffee",
|
||
"pronunciation": "/ˈɡɔnə/",
|
||
"difficulty": 2,
|
||
"usage": "非常口語化的表達,用於非正式場合"
|
||
},
|
||
...
|
||
],
|
||
"tokens_used": 1250,
|
||
"remaining_quota": 8750
|
||
}
|
||
|
||
Response 429:
|
||
{
|
||
"error": "Rate limit exceeded",
|
||
"retry_after": 60
|
||
}
|
||
|
||
Response 402:
|
||
{
|
||
"error": "Quota exceeded",
|
||
"upgrade_url": "/pricing"
|
||
}
|
||
```
|
||
|
||
### 分析文本
|
||
```http
|
||
POST /api/ai/analyze-text
|
||
Authorization: Bearer <token>
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"text": "Long dialogue from TV show...",
|
||
"analysis_type": "vocabulary" // vocabulary, grammar, culture
|
||
}
|
||
|
||
Response 200:
|
||
{
|
||
"analysis": {
|
||
"key_vocabulary": [...],
|
||
"difficulty_level": "intermediate",
|
||
"cultural_notes": [...],
|
||
"recommended_flashcards": [...]
|
||
}
|
||
}
|
||
```
|
||
|
||
## 學習統計 API
|
||
|
||
### 取得學習概覽
|
||
```http
|
||
GET /api/stats/overview
|
||
Authorization: Bearer <token>
|
||
|
||
Response 200:
|
||
{
|
||
"stats": {
|
||
"total_flashcards": 150,
|
||
"cards_due_today": 25,
|
||
"cards_reviewed_today": 15,
|
||
"streak_days": 7,
|
||
"total_study_time": 3600, // 秒
|
||
"average_accuracy": 0.85,
|
||
"cards_by_difficulty": {
|
||
"1": 30,
|
||
"2": 50,
|
||
"3": 40,
|
||
"4": 20,
|
||
"5": 10
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 取得學習進度
|
||
```http
|
||
GET /api/stats/progress?period=week
|
||
Authorization: Bearer <token>
|
||
|
||
Query Parameters:
|
||
- period: week, month, year, all
|
||
|
||
Response 200:
|
||
{
|
||
"progress": [
|
||
{
|
||
"date": "2024-01-01",
|
||
"cards_reviewed": 20,
|
||
"new_cards": 5,
|
||
"study_time": 1800,
|
||
"accuracy": 0.9
|
||
},
|
||
...
|
||
]
|
||
}
|
||
```
|
||
|
||
### 記錄學習
|
||
```http
|
||
POST /api/stats/study-session
|
||
Authorization: Bearer <token>
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"flashcard_id": "uuid",
|
||
"rating": 4, // 1-5
|
||
"response_time": 3500 // 毫秒
|
||
}
|
||
|
||
Response 200:
|
||
{
|
||
"next_review": {
|
||
"date": "2024-01-05",
|
||
"interval": 4,
|
||
"ease_factor": 2.6
|
||
}
|
||
}
|
||
```
|
||
|
||
## 標籤管理 API
|
||
|
||
### 取得標籤列表
|
||
```http
|
||
GET /api/tags
|
||
Authorization: Bearer <token>
|
||
|
||
Response 200:
|
||
{
|
||
"tags": [
|
||
{
|
||
"id": "uuid",
|
||
"name": "business",
|
||
"card_count": 25,
|
||
"color": "#3B82F6"
|
||
},
|
||
...
|
||
]
|
||
}
|
||
```
|
||
|
||
### 建立標籤
|
||
```http
|
||
POST /api/tags
|
||
Authorization: Bearer <token>
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"name": "business",
|
||
"color": "#3B82F6"
|
||
}
|
||
|
||
Response 201:
|
||
{
|
||
"tag": {
|
||
"id": "uuid",
|
||
"name": "business",
|
||
"color": "#3B82F6"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 更新標籤
|
||
```http
|
||
PUT /api/tags/:id
|
||
Authorization: Bearer <token>
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"name": "work",
|
||
"color": "#10B981"
|
||
}
|
||
|
||
Response 200:
|
||
{
|
||
"tag": {
|
||
"id": "uuid",
|
||
"name": "work",
|
||
"color": "#10B981"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 刪除標籤
|
||
```http
|
||
DELETE /api/tags/:id
|
||
Authorization: Bearer <token>
|
||
|
||
Response 204: No Content
|
||
```
|
||
|
||
## 複習系統 API
|
||
|
||
### 取得今日複習
|
||
```http
|
||
GET /api/review/today
|
||
Authorization: Bearer <token>
|
||
|
||
Response 200:
|
||
{
|
||
"cards": [
|
||
{
|
||
"id": "uuid",
|
||
"word": "Hello",
|
||
"translation": "你好",
|
||
...
|
||
}
|
||
],
|
||
"total": 25,
|
||
"completed": 10,
|
||
"remaining": 15
|
||
}
|
||
```
|
||
|
||
### 提交複習結果
|
||
```http
|
||
POST /api/review/submit
|
||
Authorization: Bearer <token>
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"flashcard_id": "uuid",
|
||
"rating": 4, // 1: 完全忘記, 2: 錯誤, 3: 困難, 4: 猶豫, 5: 簡單
|
||
"time_spent": 5000 // 毫秒
|
||
}
|
||
|
||
Response 200:
|
||
{
|
||
"next_review": "2024-01-05",
|
||
"interval": 4,
|
||
"ease_factor": 2.6,
|
||
"progress": {
|
||
"completed": 11,
|
||
"remaining": 14
|
||
}
|
||
}
|
||
```
|
||
|
||
## 錯誤碼說明
|
||
|
||
| 狀態碼 | 說明 |
|
||
|-------|------|
|
||
| 200 | 成功 |
|
||
| 201 | 建立成功 |
|
||
| 204 | 無內容(刪除成功) |
|
||
| 400 | 請求參數錯誤 |
|
||
| 401 | 未認證 |
|
||
| 403 | 無權限 |
|
||
| 404 | 資源不存在 |
|
||
| 409 | 資源衝突 |
|
||
| 429 | 請求過於頻繁 |
|
||
| 500 | 伺服器錯誤 |
|
||
|
||
## Rate Limiting
|
||
|
||
- 一般 API: 100 請求/分鐘
|
||
- AI 生成 API: 10 請求/分鐘
|
||
- 批量操作: 10 請求/分鐘
|
||
|
||
超過限制時返回 429 狀態碼,並在 `Retry-After` header 中指示等待時間。
|
||
|
||
## 分頁規範
|
||
|
||
所有列表 API 支援分頁:
|
||
|
||
```json
|
||
{
|
||
"data": [...],
|
||
"pagination": {
|
||
"total": 100,
|
||
"page": 1,
|
||
"limit": 20,
|
||
"total_pages": 5,
|
||
"has_next": true,
|
||
"has_prev": false
|
||
}
|
||
}
|
||
```
|
||
|
||
## WebSocket 事件 (未來功能)
|
||
|
||
```javascript
|
||
// 連接
|
||
ws://localhost:3000/ws
|
||
|
||
// 事件類型
|
||
{
|
||
"type": "flashcard.created",
|
||
"data": { ... }
|
||
}
|
||
|
||
// 訂閱事件
|
||
{
|
||
"action": "subscribe",
|
||
"events": ["flashcard.*", "review.completed"]
|
||
}
|
||
``` |