콘텐츠로 이동

API 클라이언트

Framedash API 클라이언트(@framedash/api-client)는 Framedash 개발자 플랫폼 REST API를 타입과 함께 다루는 TypeScript / JavaScript 클라이언트입니다. @framedash/cli@framedash/mcp-server 내부에서 사용하는 것과 동일한 클라이언트를 독립 패키지로 공개하여, Framedash 텔레메트리를 사내 도구, 대시보드, 자동화에 직접 통합할 수 있습니다.

인증, 프로젝트 범위 경로 생성, 응답 언래핑, 구조화된 오류 처리에 더해 몇 가지 보안 가드(HTTPS 전용 베이스 URL, 자격 증명을 유출하지 않는 리다이렉트 거부, 요청 타임아웃)를 내장하고 있어 데이터에 집중할 수 있습니다.

  • Node.js 18 이상(전역 fetch, AbortSignal.timeout, node: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`입니다. throw된 값은 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 필수(HTTP는 localhost / 루프백만 허용).
apiKeystring관리자 API 키. 모든 요청의 X-API-Key 헤더로 전송됩니다.
projectIdstring기본 프로젝트 UUID. projectPath()에 필수. 프로젝트 외 경로에서는 X-Project-Id 헤더로도 전송됩니다.
onError(error: ApiError) => never성공이 아닌 응답에서 호출됩니다. throw 또는 프로세스 종료가 필수입니다.

베이스 URL은 클라이언트 생성 시 검증되며, 안전하지 않거나 잘못된 URL은 즉시 throw됩니다. 동일한 검사는 공개 함수 assertSafeBaseUrl(baseUrl)로 직접 실행할 수도 있습니다.

4개의 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. 일반 HTTP는 localhost / 루프백 개발 엔드포인트를 제외하고 거부되며, 자격 증명이 포함된 URL(https://...@host)도 거부됩니다.
  • 리다이렉트 불가. API는 프로그래밍 방식의 JSON 요청을 리다이렉트하지 않으므로 모든 3xx는 오류로 처리됩니다. 클라이언트는 리다이렉트 대상으로 X-API-Key 헤더를 재전송하지 않습니다.
  • 호출당 30초 요청 타임아웃(AbortSignal.timeout 사용).
  • API 개요 — REST 엔드포인트 세부 정보
  • CLI 레퍼런스 — 이 클라이언트로 구축된 명령줄 도구
  • MCP Server — 이 클라이언트로 구축된 LLM 연동