跳到內容

API 用戶端

Framedash API 用戶端(@framedash/api-client)是用於操作 Framedash 開發者平台 REST API 的具型別 TypeScript / JavaScript 用戶端。它與 @framedash/cli@framedash/mcp-server 內部使用的用戶端相同,並以獨立套件的形式發布,方便你將 Framedash 遙測資料直接整合到自有的內部工具、儀表板與自動化流程中。

它內建了驗證、專案範圍路徑產生、回應解包與結構化錯誤處理,以及數項安全防護(僅限 HTTPS 的基礎 URL、拒絕會洩漏憑證的重新導向、請求逾時),讓你專注於資料本身。

  • Node.js 18 或更新版本(使用全域 fetchAbortSignal.timeoutnode:net
  • 用於存取 Web API 的管理員 API 金鑰(fd_admin_ 前綴)
Terminal window
npm install @framedash/api-client
import { ApiClient, ApiError } from "@framedash/api-client";
const client = new ApiClient({
baseUrl: "https://app.framedash.dev",
apiKey: process.env.FRAMEDASH_API_KEY ?? "",
projectId: process.env.FRAMEDASH_PROJECT_ID ?? "",
onError: (err: ApiError) => {
// onError 會在任何非成功回應時被呼叫,必須 throw(或結束)。
// 其回傳型別為 `never`。拋出的值會傳播到你的 await。
throw err;
},
});
// 專案範圍 GET -> /api/v1/projects/{projectId}/dashboard?days=30
const dashboard = await client.get(client.projectPath("dashboard?days=30"));
console.log(dashboard);

用戶端會自動解包 API 信封:成功的 { "success": true, "data": ... } 回應僅解析為 data

ApiClient 建構函式接收單一選項物件:

選項型別說明
baseUrlstring應用程式主機 URL(例如 https://app.framedash.dev)。必須為 HTTPS(僅 localhost / 回送允許 HTTP)。
apiKeystring管理員 API 金鑰,每次請求都透過 X-API-Key 標頭傳送。
projectIdstring預設專案 UUID。projectPath() 必填;對於非專案路徑也會作為 X-Project-Id 標頭傳送。
onError(error: ApiError) => never在任何非成功回應時呼叫。必須 throw 或結束行程。

基礎 URL 會在用戶端建構時被驗證,不安全或格式錯誤的 URL 會立即 throw。你也可以使用匯出的 assertSafeBaseUrl(baseUrl) 自行執行相同的檢查。

四個 HTTP 輔助方法涵蓋 Web API。每個都會回傳解包後的 data 負載,並可透過泛型參數指定型別:

const data = await client.get<MyType>("/api/v1/...");
await client.post("/api/v1/...", body);
await client.patch("/api/v1/...", body);
await client.delete("/api/v1/...");

大多數端點都按專案劃分。projectPath(suffix) 使用用戶端設定的 projectId 建構 /api/v1/projects/{projectId}/{suffix}:

// GET /api/v1/projects/{projectId}/status
const status = await client.get(client.projectPath("status"));
// GET /api/v1/projects/{projectId}/retention?days=30
const retention = await client.get(client.projectPath("retention?days=30"));
// GET /api/v1/projects/{projectId}/maps
const maps = await client.get(client.projectPath("maps"));

在未設定 projectId 的情況下呼叫 projectPath() 會 throw。

withProject(projectId) 會回傳綁定到另一個專案的新用戶端,重複使用相同的基礎 URL、API 金鑰與錯誤處理器。原用戶端維持不變:

const other = client.withProject("another-project-uuid");
const otherStatus = await other.get(other.projectPath("status"));
// 目前綁定的專案 ID:
console.log(client.currentProjectId);
const rows = await client.post("/api/v1/query", {
sql: "SELECT event_name, count() FROM events GROUP BY event_name",
project_id: client.currentProjectId,
limit: 100,
});
// 列出警示規則
const alerts = await client.get(client.projectPath("alerts"));
// 建立警示規則
const created = await client.post(client.projectPath("alerts"), {
name: "FPS Alert",
// ...其餘規則欄位
});
// 停用警示規則
await client.delete(client.projectPath(`alerts/${alertId}`));
// content 端點在路徑上並非專案範圍;
// 用戶端會依據設定的 projectId 自動加入 X-Project-Id 標頭。
// 批次 upsert 的請求主體會將陣列包在 entries 屬性中(每次請求最多 500 筆)。
await client.post("/api/v1/content", { entries });
const content = await client.get("/api/v1/content");

端點、查詢參數與負載結構的完整清單請參閱 API 概觀

任何非成功回應(網路錯誤、非 2xx 狀態,或缺少 success: true 的回應主體)都會被轉換為 ApiError 並傳給你的 onError 回呼。ApiError 攜帶解析後的 RFC 9457 Problem Details:

成員型別說明
statusnumberHTTP 狀態碼。
headersHeaders回應標頭(例如 X-RateLimit-Reset)。
messagestring人類可讀的錯誤訊息。
retryablebooleanAPI 是否將該錯誤標記為可重試。
retryAfternumber | undefined建議的重試間隔(秒)。
errorCategorystring | undefinedAPI 錯誤類別。
problemProblemDetails解析後的原始 Problem Details 物件。

一個考量速率限制的處理器:

const client = new ApiClient({
baseUrl: "https://app.framedash.dev",
apiKey: process.env.FRAMEDASH_API_KEY ?? "",
projectId: process.env.FRAMEDASH_PROJECT_ID ?? "",
onError: (err: ApiError): never => {
if (err.status === 429) {
const retryAfter = err.retryAfter ?? err.headers.get("X-RateLimit-Reset");
throw new Error(`Rate limited; retry after ${retryAfter}`);
}
throw err;
},
});

為避免管理員金鑰外洩,用戶端強制執行數項安全措施:

  • 僅限 HTTPS 的基礎 URL。除 localhost / 回送開發端點外,純 HTTP 會被拒絕;嵌入憑證的 URL(https://...@host)也會被拒絕。
  • 不允許重新導向。API 不會重新導向程式化的 JSON 請求,因此任何 3xx 都會被視為錯誤;用戶端不會向重新導向目標重新傳送 X-API-Key 標頭。
  • 每次呼叫 30 秒請求逾時(透過 AbortSignal.timeout)。