Fabric Apps 提供一個型別安全的 GraphQL 用戶端,讓你能在不寫原始查詢的情況下執行建立、讀取、更新和刪除操作。 客戶端會自動從你的方法呼叫產生 GraphQL,並根據你的資料模型定義回傳類型化的實體。
先決條件
- 一個定義資料模型的 Fabric Apps 專案。 參見 定義資料模型。
- 在本機執行或部署到 Fabric 的後端服務。
初始化用戶端
使用後端 URL、可發布金鑰和結構描述類型來將 RayfinClient 例項化:
import { RayfinClient } from '@microsoft/rayfin-client';
import type { Note } from '../rayfin/data/Note';
import type { Notebook } from '../rayfin/data/Notebook';
type AppSchema = {
Note: Note;
Notebook: Notebook;
};
const client = new RayfinClient<AppSchema>({
baseUrl: import.meta.env.VITE_RAYFIN_API_URL ?? 'http://localhost:5168',
publishableKey: 'pk-your-project-key',
});
generic type 參數使 TypeScript 能為所有資料操作提供自動補全與型別檢查。
讀取資料
透過 client.data.<EntityName> 存取實體集合。 流暢 API 提供查詢、篩選、排序及分頁的方法。
取得所有紀錄
const notes = await client.data.Note.select([
'id',
'title',
'content',
'createdAt',
'isPinned',
]).execute();
以主鍵取得單一記錄
const note = await client.data.Note.findByPk('00000000-0000-0000-0000-000000000000');
這會回傳完整的實體;如果不存在具有該 ID 的記錄,則回傳 null。
篩選記錄
使用以下 where() 方法篩選結果:
const pinnedNotes = await client.data.Note.select([
'id',
'title',
'isPinned',
])
.where({ isPinned: { eq: true } })
.execute();
濾波器運算元
| Operator | Description | Example |
|---|---|---|
eq |
等於 | { status: { eq: 'active' } } |
ne |
不是平等的 | { status: { ne: 'archived' } } |
gt |
大於 | { age: { gt: 18 } } |
gte |
大於或等於 | { age: { gte: 21 } } |
lt |
小於 | { price: { lt: 100 } } |
lte |
小於或等於 | { price: { lte: 50 } } |
contains |
包含子字串 | { title: { contains: 'draft' } } |
排序結果
用於 orderBy() 排序查詢結果:
const notes = await client.data.Note.select([
'id',
'title',
'createdAt',
])
.orderBy({ createdAt: 'desc' })
.execute();
依多欄排序:
const notes = await client.data.Note.select([
'id',
'title',
'isPinned',
'createdAt',
])
.orderBy({ isPinned: 'desc' })
.orderBy({ createdAt: 'desc' })
.execute();
經營人際關係
當你使用 @one() 和 @many() 裝飾器定義關聯時,可以在同一個查詢中包含相關實體的欄位:
const notes = await client.data.Note.select([
'id',
'title',
'content',
'notebook.id',
'notebook.name',
'notebook.color',
])
.execute();
每筆筆記都包含其對應的筆記本資料,無需另行查詢。
將大型結果集分頁
對於大型清單,請使用游標分頁:
const page = await client.data.Note.select([
'id',
'title',
'createdAt',
])
.orderBy({ createdAt: 'desc' })
.first(25)
.executePaginated();
console.log('Items:', page.items);
console.log('Has next page:', page.hasNextPage);
console.log('End cursor:', page.endCursor);
使用游標讀取下一頁:
if (page.hasNextPage) {
const nextPage = await client.data.Note.select([
'id',
'title',
'createdAt',
])
.orderBy({ createdAt: 'desc' })
.first(25)
.after(page.endCursor)
.executePaginated();
}
備註
totalCount 屬性會顯示於 PagedResult 類型中,但後端不會填入值。 請使用 items.length 以計算當前頁面的結果。
建立紀錄
使用 create() 此方法插入新紀錄:
const newNote = await client.data.Note.create({
title: 'Meeting notes',
content: 'Discussion points from the team sync',
isPinned: false,
isArchived: false,
createdAt: new Date(),
updatedAt: new Date(),
user_id: 'user-123',
});
該方法會回傳已建立的實體,所有欄位皆已填入值,包括自動產生的 id。
建立帶有關聯性的紀錄
建立具有關聯的實體時,請傳入完整的關聯物件,或僅包含主鍵的物件:
// Option 1: Pass just the ID
const note = await client.data.Note.create({
title: 'Weekly summary',
content: 'Summary of this week',
notebook: { id: 'notebook-456' },
isPinned: false,
isArchived: false,
createdAt: new Date(),
updatedAt: new Date(),
});
// Option 2: Pass the full object
const notebook = await client.data.Notebook.findByPk('notebook-456');
const note = await client.data.Note.create({
title: 'Weekly summary',
content: 'Summary of this week',
notebook: notebook,
isPinned: false,
isArchived: false,
createdAt: new Date(),
updatedAt: new Date(),
});
兩種形式產生相同的結果。 當你已經知道相關實體的 ID,且想避免額外擷取一次時,請使用第一種形式。
更新記錄
使用該 update() 方法修改現有紀錄。 傳入一個篩選物件,以及一個包含要更新欄位的物件:
await client.data.Note.update(
{ id: 'note-123' },
{
title: 'Updated title',
updatedAt: new Date(),
}
);
更新關係
要更改關係,請傳遞新的相關實體或僅傳遞其 ID:
// Move a note to a different notebook
await client.data.Note.update(
{ id: 'note-123' },
{ notebook: { id: 'new-notebook-789' } }
);
刪除記錄
使用 delete() 以下方法移除與篩選條件相符的紀錄:
await client.data.Note.delete({ id: 'note-123' });
當後端確認刪除時,方法就會解決。 如果沒有紀錄與濾波器相符,該方法仍然成功。
處理身份驗證
啟用認證後,請在執行資料操作前登入:
await client.auth.signIn({ email, password });
// All subsequent data calls include authentication context
const notes = await client.data.Note.select(['id', 'title']).execute();
用戶端會自動將認證會話附加到所有資料 API 呼叫中。 你不需要手動傳遞代幣。
最佳做法
- 只選擇需要的欄位 ——只取得你用來減少有效載荷大小並提升效能的欄位。
-
大型清單請使用分頁——避免一次取得數千筆記錄,請使用
first()和executePaginated()。 - 批次關係查詢 – 在同一查詢中包含相關的實體欄位,而非分別提出請求。
- 快取頻繁存取的資料 ——將靜態參考資料儲存在記憶體中,以減少 API 呼叫。
目前的限制
- 無法在 Fluent 用戶端中使用
count()方法。 選擇最小欄位並改用results.length。 - 很多關係都不被支持。 使用具有兩個
@one()導覽修飾詞的顯式聯結實體。 -
PagedResult上的totalCount屬性不會由後端填入。