dramaling-vocab-learning/docs/03_development/api/api-specification.md

15 KiB
Raw Blame History

DramaLing API 規格文檔

1. API 概述

1.1 基本資訊

  • Base URL:
    • 開發: http://localhost:3000/api
    • 生產: https://api.dramaling.com
  • 版本: v1
  • 協議: HTTPS
  • 格式: JSON
  • 認證: Bearer Token (JWT)

1.2 通用規範

請求標頭

Content-Type: application/json
Authorization: Bearer <token>
Accept-Language: zh-TW
X-Request-ID: <uuid>

響應格式

interface SuccessResponse<T> {
  success: true;
  data: T;
  meta?: {
    page?: number;
    limit?: number;
    total?: number;
    hasMore?: boolean;
  };
}

interface ErrorResponse {
  success: false;
  error: {
    code: string;
    message: string;
    details?: any;
  };
  timestamp: string;
}

HTTP 狀態碼

  • 200 OK - 請求成功
  • 201 Created - 資源創建成功
  • 204 No Content - 刪除成功
  • 400 Bad Request - 請求參數錯誤
  • 401 Unauthorized - 未認證
  • 403 Forbidden - 無權限
  • 404 Not Found - 資源不存在
  • 409 Conflict - 資源衝突
  • 422 Unprocessable Entity - 驗證失敗
  • 429 Too Many Requests - 請求過多
  • 500 Internal Server Error - 伺服器錯誤

2. 認證 API

2.1 註冊

POST /api/auth/register

請求

{
  "email": "user@example.com",
  "password": "SecurePass123!",
  "username": "johndoe"
}

響應 (201)

{
  "success": true,
  "data": {
    "user": {
      "id": "uuid",
      "email": "user@example.com",
      "username": "johndoe",
      "emailVerified": false,
      "createdAt": "2024-03-15T10:00:00Z"
    },
    "tokens": {
      "accessToken": "eyJ...",
      "refreshToken": "eyJ...",
      "expiresIn": 900
    }
  }
}

錯誤響應 (409)

{
  "success": false,
  "error": {
    "code": "EMAIL_EXISTS",
    "message": "Email already registered"
  }
}

2.2 登入

POST /api/auth/login

請求

{
  "email": "user@example.com",
  "password": "SecurePass123!",
  "rememberMe": true
}

響應 (200)

{
  "success": true,
  "data": {
    "user": {
      "id": "uuid",
      "email": "user@example.com",
      "username": "johndoe",
      "avatarUrl": "https://...",
      "lastLoginAt": "2024-03-15T10:00:00Z"
    },
    "tokens": {
      "accessToken": "eyJ...",
      "refreshToken": "eyJ...",
      "expiresIn": 2592000
    }
  }
}

2.3 Google OAuth

POST /api/auth/google

請求

{
  "idToken": "google_id_token"
}

響應 (200)

{
  "success": true,
  "data": {
    "user": {
      "id": "uuid",
      "email": "user@gmail.com",
      "username": "user",
      "provider": "google",
      "avatarUrl": "https://..."
    },
    "tokens": {
      "accessToken": "eyJ...",
      "refreshToken": "eyJ..."
    },
    "isNewUser": false
  }
}

2.4 重新整理 Token

POST /api/auth/refresh

請求

{
  "refreshToken": "eyJ..."
}

響應 (200)

{
  "success": true,
  "data": {
    "accessToken": "eyJ...",
    "refreshToken": "eyJ...",
    "expiresIn": 900
  }
}

2.5 登出

POST /api/auth/logout

請求

{
  "refreshToken": "eyJ..."
}

響應 (200)

{
  "success": true,
  "data": {
    "message": "Logged out successfully"
  }
}

2.6 忘記密碼

POST /api/auth/forgot-password

請求

{
  "email": "user@example.com"
}

響應 (200)

{
  "success": true,
  "data": {
    "message": "Password reset email sent"
  }
}

2.7 重設密碼

POST /api/auth/reset-password

請求

{
  "token": "reset_token",
  "newPassword": "NewSecurePass123!"
}

響應 (200)

{
  "success": true,
  "data": {
    "message": "Password reset successfully"
  }
}

3. 用戶 API

3.1 取得個人資料

GET /api/users/me

響應 (200)

{
  "success": true,
  "data": {
    "id": "uuid",
    "email": "user@example.com",
    "username": "johndoe",
    "avatarUrl": "https://...",
    "emailVerified": true,
    "createdAt": "2024-03-01T00:00:00Z",
    "stats": {
      "totalFlashcards": 150,
      "totalDecks": 5,
      "studyStreak": 7,
      "level": 3,
      "experience": 1250
    },
    "preferences": {
      "dailyGoal": 20,
      "reminderTime": "09:00",
      "reminderEnabled": true,
      "theme": "light",
      "language": "zh-TW"
    }
  }
}

3.2 更新個人資料

PATCH /api/users/me

請求

{
  "username": "newusername",
  "avatarUrl": "https://..."
}

響應 (200)

{
  "success": true,
  "data": {
    "id": "uuid",
    "username": "newusername",
    "avatarUrl": "https://...",
    "updatedAt": "2024-03-15T10:00:00Z"
  }
}

3.3 更新偏好設定

PUT /api/users/me/preferences

請求

{
  "dailyGoal": 30,
  "reminderTime": "20:00",
  "reminderEnabled": true,
  "theme": "dark",
  "language": "zh-TW",
  "soundEnabled": true,
  "autoPlayAudio": false
}

4. 卡組 API

4.1 取得卡組列表

GET /api/decks

查詢參數

  • page (number): 頁數,預設 1
  • limit (number): 每頁數量,預設 20
  • sort (string): 排序方式 created_at | updated_at | name
  • order (string): 排序順序 asc | desc

響應 (200)

{
  "success": true,
  "data": [
    {
      "id": "uuid",
      "name": "Business English",
      "description": "Common business vocabulary",
      "coverImage": "https://...",
      "flashcardCount": 45,
      "isPublic": false,
      "tags": ["business", "professional"],
      "createdAt": "2024-03-01T00:00:00Z",
      "updatedAt": "2024-03-15T00:00:00Z"
    }
  ],
  "meta": {
    "page": 1,
    "limit": 20,
    "total": 5,
    "hasMore": false
  }
}

4.2 取得單一卡組

GET /api/decks/{deckId}

響應 (200)

{
  "success": true,
  "data": {
    "id": "uuid",
    "name": "Business English",
    "description": "Common business vocabulary",
    "coverImage": "https://...",
    "flashcardCount": 45,
    "isPublic": false,
    "tags": ["business", "professional"],
    "flashcards": [
      {
        "id": "uuid",
        "word": "negotiate",
        "translation": "協商",
        "difficulty": "intermediate"
      }
    ],
    "createdAt": "2024-03-01T00:00:00Z"
  }
}

4.3 創建卡組

POST /api/decks

請求

{
  "name": "TOEFL Vocabulary",
  "description": "Essential TOEFL words",
  "coverImage": "https://...",
  "isPublic": false,
  "tags": ["toefl", "exam"]
}

響應 (201)

{
  "success": true,
  "data": {
    "id": "uuid",
    "name": "TOEFL Vocabulary",
    "description": "Essential TOEFL words",
    "flashcardCount": 0,
    "createdAt": "2024-03-15T10:00:00Z"
  }
}

4.4 更新卡組

PATCH /api/decks/{deckId}

請求

{
  "name": "Updated Name",
  "description": "Updated description"
}

4.5 刪除卡組

DELETE /api/decks/{deckId}

響應 (204)

無內容

5. 詞卡 API

5.1 取得詞卡列表

GET /api/flashcards

查詢參數

  • deckId (string): 卡組 ID
  • search (string): 搜尋關鍵字
  • tags (string[]): 標籤篩選
  • difficulty (string): 難度篩選
  • status (string): 學習狀態 new | learning | review | mastered
  • page (number): 頁數
  • limit (number): 每頁數量

響應 (200)

{
  "success": true,
  "data": [
    {
      "id": "uuid",
      "deckId": "uuid",
      "word": "negotiate",
      "translation": "協商",
      "definition": "To discuss something with someone in order to reach an agreement",
      "partOfSpeech": "verb",
      "pronunciation": "/nɪˈɡoʊʃieɪt/",
      "exampleSentence": "We need to negotiate a better deal.",
      "exampleTranslation": "我們需要協商一個更好的交易。",
      "difficulty": "intermediate",
      "tags": ["business", "communication"],
      "learningStatus": {
        "status": "learning",
        "nextReviewDate": "2024-03-16T00:00:00Z",
        "accuracy": 75
      }
    }
  ],
  "meta": {
    "page": 1,
    "limit": 20,
    "total": 150,
    "hasMore": true
  }
}

5.2 取得單一詞卡

GET /api/flashcards/{flashcardId}

5.3 創建詞卡

POST /api/flashcards

請求

{
  "deckId": "uuid",
  "word": "negotiate",
  "translation": "協商",
  "definition": "To discuss something with someone in order to reach an agreement",
  "partOfSpeech": "verb",
  "pronunciation": "/nɪˈɡoʊʃieɪt/",
  "exampleSentence": "We need to negotiate a better deal.",
  "exampleTranslation": "我們需要協商一個更好的交易。",
  "difficulty": "intermediate",
  "memoryTip": "Think of 'go' + 'she' + 'ate' = negotiate",
  "tags": ["business", "communication"]
}

5.4 更新詞卡

PATCH /api/flashcards/{flashcardId}

5.5 刪除詞卡

DELETE /api/flashcards/{flashcardId}

5.6 批量操作

POST /api/flashcards/bulk

請求

{
  "flashcardIds": ["uuid1", "uuid2", "uuid3"],
  "operation": "move",
  "targetDeckId": "uuid"
}

6. AI 生成 API

6.1 生成詞卡

POST /api/ai/generate

請求

{
  "text": "The quick brown fox jumps over the lazy dog...",
  "theme": "daily_conversation",
  "count": 10,
  "difficulty": "intermediate",
  "includeExamples": true,
  "targetDeckId": "uuid"
}

響應 (200)

{
  "success": true,
  "data": {
    "requestId": "uuid",
    "status": "processing",
    "estimatedTime": 5000,
    "flashcards": [
      {
        "word": "negotiate",
        "translation": "協商",
        "definition": "To discuss...",
        "pronunciation": "/nɪˈɡoʊʃieɪt/",
        "example": "We need to negotiate...",
        "difficulty": "intermediate"
      }
    ],
    "metadata": {
      "tokensUsed": 1500,
      "processingTime": 3200,
      "model": "gemini-pro"
    }
  }
}

6.2 取得生成狀態

GET /api/ai/generate/{requestId}

響應 (200)

{
  "success": true,
  "data": {
    "requestId": "uuid",
    "status": "completed",
    "flashcards": [...],
    "completedAt": "2024-03-15T10:00:05Z"
  }
}

6.3 取得用戶配額

GET /api/ai/quota

響應 (200)

{
  "success": true,
  "data": {
    "daily": {
      "used": 25,
      "limit": 50,
      "resetsAt": "2024-03-16T00:00:00Z"
    },
    "monthly": {
      "used": 500,
      "limit": 1500
    },
    "isPremium": false
  }
}

7. 學習 API

7.1 開始學習會話

POST /api/learning/sessions

請求

{
  "deckId": "uuid",
  "mode": "flashcard",
  "cardLimit": 20
}

響應 (200)

{
  "success": true,
  "data": {
    "sessionId": "uuid",
    "cards": [...],
    "totalCards": 20,
    "newCards": 5,
    "reviewCards": 15
  }
}

7.2 提交學習結果

POST /api/learning/reviews

請求

{
  "sessionId": "uuid",
  "flashcardId": "uuid",
  "rating": 4,
  "timeSpent": 15,
  "isCorrect": true
}

響應 (200)

{
  "success": true,
  "data": {
    "nextReviewDate": "2024-03-18T00:00:00Z",
    "interval": 3,
    "easeFactor": 2.5,
    "repetitions": 2
  }
}

7.3 取得待複習詞卡

GET /api/learning/due

查詢參數

  • deckId (string): 特定卡組
  • limit (number): 數量限制

響應 (200)

{
  "success": true,
  "data": {
    "dueCards": [...],
    "newCards": [...],
    "totalDue": 25,
    "totalNew": 10
  }
}

7.4 結束學習會話

POST /api/learning/sessions/{sessionId}/complete

響應 (200)

{
  "success": true,
  "data": {
    "summary": {
      "cardsStudied": 20,
      "correctAnswers": 18,
      "accuracy": 90,
      "timeSpent": 600,
      "experience": 100,
      "streakDays": 8
    }
  }
}

8. 統計 API

8.1 取得學習統計

GET /api/stats

查詢參數

  • period (string): daily | weekly | monthly | yearly
  • startDate (string): YYYY-MM-DD
  • endDate (string): YYYY-MM-DD

響應 (200)

{
  "success": true,
  "data": {
    "overview": {
      "totalCards": 500,
      "masteredCards": 200,
      "learningCards": 250,
      "newCards": 50,
      "studyStreak": 15,
      "totalStudyTime": 12000
    },
    "daily": [
      {
        "date": "2024-03-15",
        "cardsStudied": 30,
        "newCards": 5,
        "reviewCards": 25,
        "accuracy": 85,
        "studyTime": 45
      }
    ],
    "heatmap": {
      "2024-03-15": 3,
      "2024-03-14": 2,
      "2024-03-13": 4
    }
  }
}

8.2 取得成就列表

GET /api/stats/achievements

響應 (200)

{
  "success": true,
  "data": {
    "unlocked": [
      {
        "id": "first_card",
        "name": "First Step",
        "description": "Create your first flashcard",
        "icon": "🎯",
        "unlockedAt": "2024-03-01T00:00:00Z",
        "points": 10
      }
    ],
    "inProgress": [
      {
        "id": "week_streak",
        "name": "Week Warrior",
        "description": "Study for 7 days in a row",
        "progress": 85,
        "target": 7,
        "current": 6
      }
    ],
    "totalPoints": 250
  }
}

9. 錯誤處理

9.1 錯誤碼列表

錯誤碼 HTTP 狀態 描述
UNAUTHORIZED 401 未認證
FORBIDDEN 403 無權限
NOT_FOUND 404 資源不存在
VALIDATION_ERROR 422 驗證失敗
EMAIL_EXISTS 409 Email 已存在
USERNAME_EXISTS 409 用戶名已存在
INVALID_CREDENTIALS 401 認證資訊錯誤
TOKEN_EXPIRED 401 Token 過期
RATE_LIMIT_EXCEEDED 429 請求過多
QUOTA_EXCEEDED 402 配額超限
AI_SERVICE_ERROR 503 AI 服務錯誤
DATABASE_ERROR 500 資料庫錯誤

9.2 錯誤響應範例

{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Validation failed",
    "details": {
      "email": "Invalid email format",
      "password": "Password must be at least 8 characters"
    }
  },
  "timestamp": "2024-03-15T10:00:00Z"
}

10. Rate Limiting

10.1 限制規則

  • 一般 API: 100 requests/minute
  • AI 生成: 10 requests/minute
  • 認證相關: 5 requests/minute

10.2 響應標頭

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1710496800

10.3 超限響應 (429)

{
  "success": false,
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Too many requests",
    "retryAfter": 60
  }
}

11. Webhook

11.1 事件類型

  • user.created - 新用戶註冊
  • flashcard.generated - AI 生成完成
  • achievement.unlocked - 成就解鎖
  • subscription.updated - 訂閱更新

11.2 Webhook 格式

{
  "id": "evt_uuid",
  "type": "flashcard.generated",
  "created": "2024-03-15T10:00:00Z",
  "data": {
    "requestId": "uuid",
    "userId": "uuid",
    "flashcardCount": 10
  }
}

11.3 簽名驗證

const signature = req.headers['x-webhook-signature'];
const payload = JSON.stringify(req.body);
const expected = crypto
  .createHmac('sha256', WEBHOOK_SECRET)
  .update(payload)
  .digest('hex');

if (signature !== expected) {
  throw new Error('Invalid signature');
}