Chuyển đến nội dung

Tích Hợp

Các pattern tích hợp ở cấp độ framework cho cả hai SDK. TypeScript bao gồm React, Next.js, và Node.js thuần; Python bao gồm FastAPI, asyncio, Django, và Celery. Luồng OTP login được ghi lại cho cả hai.

Để biết chiến lược credential (api key vs access token, env vars), xem Xác ThựcHướng Dẫn Cài Đặt.


React (TypeScript)

Singleton Client

Tạo client một lần bên ngoài component tree và tái sử dụng. Token trong localStorage đến từ luồng OTP login.

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

Custom Hook Fetch Data

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>Đang tải...</p>;
if (error) return <p>Lỗi: {error.message}</p>;
return (
<ul>
{products.map((p) => (
<li key={p.id}>{p.name}{p.price} {p.currency}</li>
))}
</ul>
);
}

Next.js (TypeScript)

API Route (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 nên được set theo cách platform deploy của bạn. Xem Hướng Dẫn Cài Đặt → Cấu hình credentials.

Server Component (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>Sản Phẩm</h1>
<ul>{products.map((p) => <li key={p.id}>{p.name}</li>)}</ul>
</main>
);
}

Node.js CLI Script (TypeScript)

Cho các script one-shot (data exports, backfills, ad-hoc queries):

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(`Đã xuất ${contacts.length} liên hệ`);
}
exportContacts().catch(console.error);
Terminal window
npx ts-node scripts/export-contacts.ts

FastAPI (Python)

Per-request Dependency Injection

Pattern đơn giản nhất — một async client per request, lifetime được quản lý bởi dependency:

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}],
)

Global Singleton (Tái Sử Dụng Connection Pool)

Để đạt throughput cao hơn, chia sẻ một client cho suốt vòng đời ứng dụng:

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() # health check khi khởi động
yield
await imbrace.close()
app = FastAPI(lifespan=lifespan)
@app.get("/me")
async def get_me():
return await imbrace.platform.get_me()

asyncio (Python)

Concurrent Requests

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())

Streaming 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": "Giải thích async/await trong Python."}],
):
content = chunk["choices"][0]["delta"].get("content", "")
print(content, end="", flush=True)
asyncio.run(stream_response())

Django (Python)

Synchronous View

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

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)

Với background task workers, tạo client bên trong mỗi task — không chia sẻ giữa các 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)

Luồng OTP Login

Luồng OTP về mặt khái niệm giống nhau ở cả hai SDK: yêu cầu OTP cho email, rồi đổi lấy access token. Xem Xác Thực → luồng OTP login để xem toàn bộ vòng đời credential.

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 không đúng");
}
}
return step === "email" ? (
<div>
<input value={email} onChange={(e) => setEmail(e.target.value)} placeholder="Email" />
<button onClick={requestOtp}>Gửi OTP</button>
</div>
) : (
<div>
<input value={otp} onChange={(e) => setOtp(e.target.value)} placeholder="Nhập OTP" />
<button onClick={verifyOtp}>Xác nhận</button>
</div>
);
}