框架整合
兩個 SDK 的框架級接線模式。TypeScript 部分涵蓋 React、Next.js 和 Node.js;Python 部分涵蓋 FastAPI、asyncio、Django 和 Celery。OTP 登入流程為兩者均有記錄。
憑證策略(api key vs access token、env vars),參閱身份驗證和安裝指南。
React (TypeScript)
單例客戶端
在元件樹外建立一次客戶端並重用。localStorage 中的 token 來自 OTP 登入流程。
import { ImbraceClient } from "@imbrace/sdk";
export const client = new ImbraceClient({ accessToken: typeof window !== "undefined" ? (localStorage.getItem("imbrace_token") ?? undefined) : undefined,});資料擷取 Hook
import { useState, useEffect } from "react";import { client } from "@/lib/imbrace";import type { Product } from "@imbrace/sdk";
export function useProducts(category?: string) { const [products, setProducts] = useState<Product[]>([]); const [loading, setLoading] = useState(true); const [error, setError] = useState<Error | null>(null);
useEffect(() => { setLoading(true); client.marketplace .listProducts({ category }) .then((res) => setProducts(res.data)) .catch(setError) .finally(() => setLoading(false)); }, [category]);
return { products, loading, error };}import { useProducts } from "@/hooks/useProducts";
export function ProductList() { const { products, loading, error } = useProducts("electronics"); if (loading) return <p>載入中...</p>; if (error) return <p>錯誤:{error.message}</p>; return ( <ul> {products.map((p) => ( <li key={p.id}>{p.name} — {p.price} {p.currency}</li> ))} </ul> );}Next.js (TypeScript)
API 路由(App Router)
import { NextResponse } from "next/server";import { ImbraceClient } from "@imbrace/sdk";
const client = new ImbraceClient({ apiKey: process.env.IMBRACE_API_KEY,});
export async function GET(request: Request) { const { searchParams } = new URL(request.url); const category = searchParams.get("category") ?? undefined; const { data } = await client.marketplace.listProducts({ category }); return NextResponse.json(data);}
export async function POST(request: Request) { const body = await request.json(); const product = await client.marketplace.createProduct(body); return NextResponse.json(product, { status: 201 });}process.env.IMBRACE_API_KEY 應按你的部署平台的方式設定。參閱安裝指南 → 設定憑證。
伺服器端元件(App Router)
import { ImbraceClient } from "@imbrace/sdk";
const client = new ImbraceClient({ apiKey: process.env.IMBRACE_API_KEY,});
export default async function ProductsPage() { const { data: products } = await client.marketplace.listProducts({ limit: 20 }); return ( <main> <h1>商品</h1> <ul>{products.map((p) => <li key={p.id}>{p.name}</li>)}</ul> </main> );}Node.js CLI 腳本 (TypeScript)
適用於一次性腳本(資料匯出、回填、臨時查詢):
import { ImbraceClient } from "@imbrace/sdk";import { writeFileSync } from "fs";
const client = new ImbraceClient();
async function exportContacts() { const { data: contacts } = await client.contacts.list({ limit: 1000 }); writeFileSync("contacts.json", JSON.stringify(contacts, null, 2)); console.log(`已匯出 ${contacts.length} 個聯絡人`);}
exportContacts().catch(console.error);npx ts-node scripts/export-contacts.tsFastAPI (Python)
Per-request 依賴注入
最簡單的模式 — 每個請求一個 async client,由依賴項管理生命週期:
from fastapi import FastAPI, Dependsfrom imbrace import AsyncImbraceClient
app = FastAPI()
async def get_imbrace() -> AsyncImbraceClient: async with AsyncImbraceClient() as client: yield client
@app.get("/products")async def list_products(client: AsyncImbraceClient = Depends(get_imbrace)): result = await client.marketplace.list_products(limit=20) return result["data"]
@app.get("/products/{product_id}")async def get_product(product_id: str, client: AsyncImbraceClient = Depends(get_imbrace)): return await client.marketplace.get_product(product_id)
@app.post("/ai/chat")async def chat(message: str, client: AsyncImbraceClient = Depends(get_imbrace)): return await client.ai.complete( model="gpt-4o", messages=[{"role": "user", "content": message}], )全域單例(提高連線重用)
對於更高吞吐量,在應用程式生命週期內共享一個 client:
from contextlib import asynccontextmanagerfrom fastapi import FastAPIfrom imbrace import AsyncImbraceClient
imbrace: AsyncImbraceClient = None # type: ignore
@asynccontextmanagerasync def lifespan(app: FastAPI): global imbrace imbrace = AsyncImbraceClient() await imbrace.init() # 啟動時健康檢查 yield await imbrace.close()
app = FastAPI(lifespan=lifespan)
@app.get("/me")async def get_me(): return await imbrace.platform.get_me()asyncio (Python)
並發請求
import asynciofrom imbrace import AsyncImbraceClient
async def fetch_dashboard_data(): async with AsyncImbraceClient() as client: me, products, channels = await asyncio.gather( client.platform.get_me(), client.marketplace.list_products(limit=5), client.channel.list_channels(type="group"), ) return { "user": me, "products": products["data"], "channels": channels["data"], }
data = asyncio.run(fetch_dashboard_data())串流 AI
import asynciofrom imbrace import AsyncImbraceClient
async def stream_response(): async with AsyncImbraceClient() as client: async for chunk in client.ai.stream( model="gpt-4o", messages=[{"role": "user", "content": "解釋 Python 中的 async/await。"}], ): content = chunk["choices"][0]["delta"].get("content", "") print(content, end="", flush=True)
asyncio.run(stream_response())Django (Python)
同步視圖
from django.http import JsonResponsefrom imbrace import ImbraceClient, ApiError
def product_list(request): with ImbraceClient() as client: try: result = client.marketplace.list_products( category=request.GET.get("category"), page=int(request.GET.get("page", 1)), ) return JsonResponse(result) except ApiError as e: return JsonResponse({"error": str(e)}, status=e.status_code)Django 設定整合
IMBRACE_API_KEY = env("IMBRACE_API_KEY")IMBRACE_ENV = env("IMBRACE_ENV", default="stable")
# utils/imbrace.pyfrom django.conf import settingsfrom imbrace import ImbraceClient
def get_client() -> ImbraceClient: return ImbraceClient( api_key=settings.IMBRACE_API_KEY, env=settings.IMBRACE_ENV, )Celery (Python)
對於背景任務 workers,在每個 task 內部建立 client — 不要在 worker 之間共享:
from celery import Celeryfrom imbrace import ImbraceClient, NetworkError
app = Celery("tasks")
@app.task(bind=True, max_retries=3)def sync_products(self): try: with ImbraceClient() as client: result = client.marketplace.list_products(limit=100) for product in result["data"]: save_to_db(product) except NetworkError as exc: raise self.retry(exc=exc, countdown=2 ** self.request.retries)OTP 登入流程
OTP 流程在兩個 SDK 中概念上相同:為電子郵件請求 OTP,然後交換為 access token。參閱身份驗證 → OTP 登入流程了解完整的憑證生命週期。
import { useState } from "react";import { ImbraceClient, AuthError } from "@imbrace/sdk";
const client = new ImbraceClient();
export function LoginForm() { const [email, setEmail] = useState(""); const [otp, setOtp] = useState(""); const [step, setStep] = useState<"email" | "otp">("email");
async function requestOtp() { await client.requestOtp(email); setStep("otp"); }
async function verifyOtp() { try { await client.loginWithOtp(email, otp); window.location.href = "/dashboard"; } catch (e) { if (e instanceof AuthError) alert("OTP 不正確"); } }
return step === "email" ? ( <div> <input value={email} onChange={(e) => setEmail(e.target.value)} placeholder="電子郵件" /> <button onClick={requestOtp}>發送 OTP</button> </div> ) : ( <div> <input value={otp} onChange={(e) => setOtp(e.target.value)} placeholder="輸入 OTP" /> <button onClick={verifyOtp}>確認</button> </div> );}from fastapi import FastAPI, HTTPExceptionfrom pydantic import BaseModelfrom imbrace import AsyncImbraceClient, AuthError
app = FastAPI()
class OtpRequest(BaseModel): email: str
class OtpVerify(BaseModel): email: str otp: str
@app.post("/auth/request-otp")async def request_otp(body: OtpRequest): async with AsyncImbraceClient() as client: await client.request_otp(body.email) return {"message": "OTP 已發送"}
@app.post("/auth/verify-otp")async def verify_otp(body: OtpVerify): async with AsyncImbraceClient() as client: try: await client.login_with_otp(body.email, body.otp) token = client._token_manager.get_token() return {"access_token": token} except AuthError: raise HTTPException(status_code=401, detail="OTP 不正確")