convertor/api-server/docs/API_SPEC.md

12 KiB
Raw Blame History

ConvertX API 規格文件

概述

ConvertX API Server 是一個獨立的檔案轉換 API 服務,同時提供 REST API 和 GraphQL API。 兩種 API 是完全獨立的服務,使用者可以選擇只使用其中一種。

認證

JWT Bearer Token

所有 API 請求(除了健康檢查)都需要在 HTTP Header 中提供有效的 JWT Token

Authorization: Bearer <jwt-token>

Token 結構

{
  "sub": "user-unique-id",
  "exp": 1735689600,
  "iat": 1735603200,
  "email": "user@example.com",
  "roles": ["user", "admin"]
}
欄位 必填 說明
sub 使用者唯一識別碼
exp Token 過期時間Unix timestamp
iat Token 簽發時間Unix timestamp
email - 使用者 Email
roles - 使用者角色列表

認證錯誤回應

狀況 錯誤碼 HTTP 狀態
缺少 Authorization Header MISSING_AUTH_HEADER 401
Token 格式錯誤 INVALID_TOKEN 401
Token 簽名無效 INVALID_TOKEN 401
Token 已過期 TOKEN_EXPIRED 401

REST API 規格

基礎資訊

  • Base URL: http://localhost:3001/api/v1
  • Content-Type: application/json(一般請求)或 multipart/form-data(檔案上傳)

健康檢查

GET /healthGET /api/v1/health

檢查 API Server 運作狀態。不需要認證。

回應

{
  "status": "healthy",
  "version": "0.1.0",
  "timestamp": "2024-01-15T10:30:00Z"
}

引擎管理

GET /api/v1/engines

列出所有可用的轉換引擎。

Headers

Authorization: Bearer <token>

回應

{
  "engines": [
    {
      "id": "ffmpeg",
      "name": "FFmpeg",
      "description": "Audio and video conversion using FFmpeg",
      "supported_input_formats": [
        "mp4",
        "webm",
        "avi",
        "mkv",
        "mov",
        "mp3",
        "wav",
        "flac",
        "ogg",
        "m4a",
        "gif"
      ],
      "supported_output_formats": [
        "webm",
        "avi",
        "mkv",
        "mov",
        "mp3",
        "wav",
        "flac",
        "ogg",
        "gif",
        "m4a",
        "aac",
        "mp4"
      ]
    },
    {
      "id": "imagemagick",
      "name": "ImageMagick",
      "description": "Image format conversion using ImageMagick",
      "supported_input_formats": ["png", "jpg", "jpeg", "gif", "bmp", "webp", "tiff", "svg"],
      "supported_output_formats": ["jpg", "jpeg", "gif", "bmp", "webp", "tiff", "ico", "pdf", "png"]
    }
  ]
}

GET /api/v1/engines/:engine_id

取得特定引擎的詳細資訊。

參數

  • engine_id: 引擎識別碼(如 ffmpeg, imagemagick

回應 (200)

{
  "id": "ffmpeg",
  "name": "FFmpeg",
  "description": "Audio and video conversion using FFmpeg",
  "supported_input_formats": ["mp4", "webm", "avi"],
  "supported_output_formats": ["mp4", "webm", "mp3"]
}

回應 (404)

{
  "error": {
    "code": "ENGINE_NOT_FOUND",
    "message": "Engine not found: nonexistent"
  }
}

GET /api/v1/engines/:engine_id/conversions

取得特定引擎支援的轉換對應表。

回應

{
  "engine_id": "ffmpeg",
  "conversions": {
    "mp4": ["webm", "avi", "mkv", "mov", "mp3", "wav", "flac", "ogg", "gif"],
    "webm": ["mp4", "avi", "mkv", "mov", "mp3", "wav", "flac", "ogg", "gif"],
    "mp3": ["wav", "flac", "ogg", "m4a", "aac"]
  }
}

轉檔任務

POST /api/v1/convert

建立新的轉檔任務。

Headers

Authorization: Bearer <token>
Content-Type: multipart/form-data

表單欄位

欄位 類型 必填 說明
file File 要轉換的檔案
engine String 轉換引擎 ID
target_format String 目標格式(不含點)
options String - JSON 格式的轉換選項

回應 (201)

{
  "job_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "pending",
  "message": "Conversion job created successfully"
}

回應 (422) - 不支援的轉換

{
  "error": {
    "code": "UNSUPPORTED_CONVERSION",
    "message": "Unsupported conversion from pdf to mp4 using engine ffmpeg",
    "suggestions": [
      {
        "engine": "libreoffice",
        "from": "pdf",
        "to": "docx"
      },
      {
        "engine": "libreoffice",
        "from": "pdf",
        "to": "html"
      },
      {
        "engine": "calibre",
        "from": "pdf",
        "to": "epub"
      }
    ]
  }
}

GET /api/v1/jobs

列出當前使用者的所有任務。

回應

{
  "jobs": [
    {
      "job_id": "550e8400-e29b-41d4-a716-446655440000",
      "status": "completed",
      "original_filename": "video.mp4",
      "source_format": "mp4",
      "target_format": "webm",
      "engine": "ffmpeg",
      "download_url": "/api/v1/jobs/550e8400-e29b-41d4-a716-446655440000/download",
      "created_at": "2024-01-15T10:00:00Z",
      "completed_at": "2024-01-15T10:01:30Z"
    }
  ],
  "total": 1
}

GET /api/v1/jobs/:job_id

取得特定任務的狀態。

任務狀態

狀態 說明
pending 等待處理
processing 處理中
completed 完成
failed 失敗

回應 (200) - 完成

{
  "job_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "original_filename": "video.mp4",
  "source_format": "mp4",
  "target_format": "webm",
  "engine": "ffmpeg",
  "download_url": "/api/v1/jobs/550e8400-e29b-41d4-a716-446655440000/download",
  "created_at": "2024-01-15T10:00:00Z",
  "completed_at": "2024-01-15T10:01:30Z"
}

回應 (200) - 失敗

{
  "job_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "failed",
  "original_filename": "corrupted.mp4",
  "source_format": "mp4",
  "target_format": "webm",
  "engine": "ffmpeg",
  "error_message": "Conversion failed: Invalid data found when processing input",
  "created_at": "2024-01-15T10:00:00Z",
  "completed_at": "2024-01-15T10:00:05Z"
}

GET /api/v1/jobs/:job_id/download

下載轉換後的檔案。

前提條件

  • 任務狀態必須是 completed
  • 只有任務建立者可以下載

回應 Headers

Content-Type: <mime-type>
Content-Disposition: attachment; filename="output.webm"

錯誤回應

狀況 錯誤碼 HTTP 狀態
任務未完成 BAD_REQUEST 400
無權限 UNAUTHORIZED 401
任務不存在 JOB_NOT_FOUND 404
檔案遺失 FILE_NOT_FOUND 404

DELETE /api/v1/jobs/:job_id

刪除任務及相關檔案。

回應 (200)

{
  "message": "Job deleted successfully",
  "job_id": "550e8400-e29b-41d4-a716-446655440000"
}

GraphQL API 規格

Endpoint

  • URL: http://localhost:3001/graphql
  • Method: POST
  • Content-Type: application/json

GraphQL Playground 可透過 GET 請求訪問同一 URL。

Schema

# ========== Queries ==========

type Query {
  """
  健康檢查不需認證
  """
  health: Health!

  """
  列出所有可用引擎
  """
  engines: [Engine!]!

  """
  取得特定引擎
  """
  engine(id: ID!): Engine

  """
  列出當前使用者的所有任務
  """
  jobs: [Job!]!

  """
  取得特定任務
  """
  job(id: ID!): Job

  """
  驗證轉換是否支援
  """
  validateConversion(engine: String!, from: String!, to: String!): CreateJobResult!

  """
  取得轉換建議
  """
  suggestions(from: String!, to: String!): [Suggestion!]!
}

# ========== Mutations ==========

type Mutation {
  """
  建立轉檔任務
  """
  createJob(filename: String!, fileBase64: String!, input: CreateJobInput!): CreateJobResult!

  """
  刪除任務
  """
  deleteJob(id: ID!): Boolean!
}

# ========== Input Types ==========

input CreateJobInput {
  """
  轉換引擎 ID
  """
  engine: String!

  """
  目標格式
  """
  targetFormat: String!

  """
  轉換選項JSON 字串
  """
  options: String
}

# ========== Object Types ==========

type Health {
  status: String!
  version: String!
  timestamp: DateTime!
}

type Engine {
  id: ID!
  name: String!
  description: String!
  supportedInputFormats: [String!]!
  supportedOutputFormats: [String!]!
}

type Job {
  id: ID!
  originalFilename: String!
  sourceFormat: String!
  targetFormat: String!
  engine: String!
  status: JobStatus!
  outputFilename: String
  errorMessage: String
  downloadUrl: String
  createdAt: DateTime!
  completedAt: DateTime
}

type Suggestion {
  engine: String!
  from: String!
  to: String!
}

type CreateJobResult {
  success: Boolean!
  job: Job
  error: ConversionError
}

type ConversionError {
  code: String!
  message: String!
  suggestions: [Suggestion!]!
}

# ========== Enums ==========

enum JobStatus {
  PENDING
  PROCESSING
  COMPLETED
  FAILED
}

# ========== Scalars ==========

scalar DateTime

使用範例

列出所有引擎

query {
  engines {
    id
    name
    description
    supportedInputFormats
    supportedOutputFormats
  }
}

驗證轉換是否支援

query {
  validateConversion(engine: "ffmpeg", from: "mp4", to: "webm") {
    success
    error {
      code
      message
      suggestions {
        engine
        from
        to
      }
    }
  }
}

取得轉換建議

query {
  suggestions(from: "pdf", to: "docx") {
    engine
    from
    to
  }
}

建立轉檔任務

mutation CreateConversionJob($filename: String!, $content: String!) {
  createJob(
    filename: $filename
    fileBase64: $content
    input: { engine: "imagemagick", targetFormat: "jpg" }
  ) {
    success
    job {
      id
      status
      originalFilename
    }
    error {
      code
      message
      suggestions {
        engine
        from
        to
      }
    }
  }
}

Variables:

{
  "filename": "image.png",
  "content": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="
}

查詢任務狀態

query {
  job(id: "550e8400-e29b-41d4-a716-446655440000") {
    id
    status
    originalFilename
    sourceFormat
    targetFormat
    engine
    downloadUrl
    errorMessage
    createdAt
    completedAt
  }
}

列出所有任務

query {
  jobs {
    id
    status
    originalFilename
    targetFormat
    downloadUrl
  }
}

刪除任務

mutation {
  deleteJob(id: "550e8400-e29b-41d4-a716-446655440000")
}

錯誤碼對照表

錯誤碼 HTTP 狀態 說明 包含建議
UNAUTHORIZED 401 未授權存取
INVALID_TOKEN 401 Token 無效
TOKEN_EXPIRED 401 Token 已過期
MISSING_AUTH_HEADER 401 缺少認證標頭
BAD_REQUEST 400 請求格式錯誤
INVALID_FILE 400 無法辨識檔案格式
FILE_TOO_LARGE 400 檔案超過大小限制
ENGINE_NOT_FOUND 404 引擎不存在
JOB_NOT_FOUND 404 任務不存在
FILE_NOT_FOUND 404 檔案不存在
UNSUPPORTED_CONVERSION 422 不支援的轉換
CONVERSION_FAILED 500 轉換失敗
INTERNAL_ERROR 500 內部錯誤