Fabric 앱은 원시 쿼리를 작성하지 않고도 만들기, 읽기, 업데이트 및 삭제 작업을 수행할 수 있는 형식이 안전한 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',
});
제네릭 형식 인수를 사용하면 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');
이렇게 하면 전체 엔터티가 반환되거나 null 해당 ID가 있는 레코드가 없는 경우 반환됩니다.
레코드 필터링
메서드를 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();
각 노트에는 별도의 쿼리 없이 연결된 Notebook 데이터가 포함됩니다.
큰 결과 집합 페이지 매김
큰 목록에 커서 기반 페이지 매김을 사용합니다.
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 호출을 줄이기 위해 메모리에 정적 참조 데이터를 저장합니다.
현재 제한 사항
-
count()메서드는 Fluent 클라이언트에서 사용할 수 없습니다. 최소 필드를 선택하고 대신 사용합니다results.length. - 다대다 관계는 지원되지 않습니다. 두 개의
@one()탐색 데코레이터가 있는 명시적 조인 엔터티를 사용합니다. -
PagedResult의totalCount속성은 백엔드에서 값이 채워지지 않습니다.