跳到內容

框架整合

兩個 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 登入流程

lib/imbrace.ts
import { ImbraceClient } from "@imbrace/sdk";
export const client = new ImbraceClient({
accessToken:
typeof window !== "undefined"
? (localStorage.getItem("imbrace_token") ?? undefined)
: undefined,
});

資料擷取 Hook

hooks/useProducts.ts
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 };
}
components/ProductList.tsx
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)

app/api/products/route.ts
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)

app/products/page.tsx
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)

適用於一次性腳本(資料匯出、回填、臨時查詢):

scripts/export-contacts.ts
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);
Terminal window
npx ts-node scripts/export-contacts.ts

FastAPI (Python)

Per-request 依賴注入

最簡單的模式 — 每個請求一個 async client,由依賴項管理生命週期:

from fastapi import FastAPI, Depends
from 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 asynccontextmanager
from fastapi import FastAPI
from imbrace import AsyncImbraceClient
imbrace: AsyncImbraceClient = None # type: ignore
@asynccontextmanager
async 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 asyncio
from 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 asyncio
from 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)

同步視圖

views.py
from django.http import JsonResponse
from 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 設定整合

settings.py
IMBRACE_API_KEY = env("IMBRACE_API_KEY")
IMBRACE_ENV = env("IMBRACE_ENV", default="stable")
# utils/imbrace.py
from django.conf import settings
from 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 之間共享:

tasks.py
from celery import Celery
from 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 登入流程了解完整的憑證生命週期。

components/LoginForm.tsx
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>
);
}