Oversikt over programmeringsmodellen

Rayfin SDK bruker en dekoratordrevet programmeringsmodell hvor du definerer dataskjemaet ditt én gang i TypeScript og automatisk mottar produksjonsklare API-er, typesikre klienter og infrastruktur.

Nøkkelkonsepter

Rayfin SDK kombinerer tre kjerneelementer:

  • Decorator-drevet skjema: Bruk TypeScript-decoratorer for å definere datamodeller, tillatelser og relasjoner.
  • Automatisk API-generering: Dine dekorerte klasser blir GraphQL-endepunkter uten å skrive kontrollerkode.
  • Type-sikre klienter: Genererte TypeScript-klienter gir kompilasjonsvalidering for spørringer og mutasjoner.

Slik fungerer det

Når du lager en Fabric-app, flyter koden din gjennom disse stadiene:

# Etappe Hva som skjer
1 Developer Du lager appen i din valgte editor.
2 TypeScript Du skriver entitetsklasser i TypeScript.
3 Decorators Du annoterer klasser og felt med @entity, @uuid, @text, , @roleog andre dekoratører.
4 Schema CLI-en kompilerer de dekorerte klassene til et databaseskjema, tillatelsespolicyer og API-konfigurasjon.
5 API-er Skjemaet publiseres som GraphQL-endepunkter.
6 Klient Den genererte RayfinClient eksponerer en typesikker data- og autentiseringsklient over disse endepunktene.
7 Bruksområde Frontend-applikasjonen din bruker klienten for å lese og skrive data.

1. Definer datamodeller med dekoratorer

Du definerer datastrukturen din ved å bruke TypeScript-klasser og dekoratorer fra @microsoft/rayfin-core:

import { entity, uuid, text, int } from '@microsoft/rayfin-core';

@entity()
export class Product {
  @uuid() id!: string;
  @text() name!: string;
  @text({ optional: true }) description?: string;
  @int() price!: number;
}

2. Skjemagenerering

Rayfin CLI (npx rayfin) analyserer dine dekorerte klasser og genererer:

  • Databaseskjema – Tabeller, kolonner, begrensninger og indekser
  • API-konfigurasjon - GraphQL-endepunktdefinisjoner
  • Tillatelsespolicyer - Sikkerhet på radnivå og tilgangskontroll på feltnivå

4. Typesikker klientbruk

GraphQL-API-er er tilgjengelige for å utføre CRUD-operasjoner på databasen din. Rayfin SDK tilbyr en dataklientoperasjon rett ut av boksen for å lese, skrive eller slette data.

import { RayfinClient } from '@microsoft/rayfin-client';

const client = new RayfinClient();

// TypeScript knows about Product fields
const products = await client.data.products.query()
  .select(['id', 'name', 'price'])
  .execute();

// Compile-time error if field doesn't exist
const invalid = await client.data.products.query()
  .select(['nonexistentField'])  // ❌ TypeScript error
  .execute();

Referanse til dekoratør

Rayfin SDK tilbyr dekoratorer for vanlige datamodelleringsmønstre:

Entitetsdekoratører

Dekoratør Formål Eksempel
@entity() Merk en klasse som en databaseenhet @entity() class Product

Eiendomsdekoratører

Dekoratør Databasetype TypeScript-type
@uuid() UNIQUEIDENTIFIER string
@text() NVARCHAR string
@int() INT number
@decimal() DESIMAL number
@bool() BIT boolean
@date() DATETIME2 Date

Tillatelsesdekoratører

Dekoratør Formål
@role() Definer rollebaserte tillatelser

Se Definer datatillatelser for autorisasjonsdetaljer.

Functions

Lag én UserDataFunctions instans, og registrer hver funksjon ved å kalle udf.func(name, handler, connections?).

Følg disse reglene når du definerer en funksjon:

  • Plasser parameteren hvor som RayfinContext helst i handlersignaturen. Kjøretiden identifiserer den etter type, injiserer den, og ekskluderer den fra de genererte funksjonsinputene.
  • Deklarer en tilkobling for hver delegert token funksjonen trenger. Utelat tilkoblingsarrayet for funksjoner som kun får tilgang til appdata eller ikke trenger delegerte tokens.

Følgende eksempel registrerer en vanlig funksjon og en funksjon som bruker invokasjonskonteksten:

import {
  UserDataFunctions,
  type RayfinContext,
} from '@microsoft/fabric-user-data-functions';

// Match rayfin/data/schema.ts so getDataClient() is fully typed.
import type { TripPlan } from '../../data/TripPlan.js';

type AppSchema = { TripPlan: TripPlan };

const udf = new UserDataFunctions();

udf.func('greet', async (name: string): Promise<string> => {
  return `Hello, ${name}!`;
});

udf.func(
  'whoAmI',
  async (ctx: RayfinContext<AppSchema>): Promise<string> => {
    return ctx.accessToken ? 'authenticated' : 'anonymous';
  },
);

Tilbyr RayfinContext funksjonens kjøretidstjenester:

Medlem Formål
ctx.accessToken Gir den innloggede brukerens Rayfin JSON Web Token (JWT). Dekode kravet sub for å få en stabil bruker-ID.
ctx.Tokens.<Audience> Får en plattformbasert ressurstoken for et publikum som er deklarert i annotasjonen RayfinContext . Distribuerte funksjoner bruker appens identitet og dens tillatelser. For detaljer, se Koble funksjoner til eksterne ressurser.
ctx.getSecret('NAME') Får en hemmelighet for den nåværende invokasjonen. Kommer tilbake undefined når hemmeligheten ikke er satt.
ctx.getDataClient() Henter det typede data-API-et for enhetene dine. Klienten støtter opprettelse, findManyoppdatering, sletting og oppgradering av operasjoner.
ctx.baseUrl Gir Rayfin-endepunktet for det nåværende elementet.
ctx.publishableKey Gir den publiserbare nøkkelen for det nåværende elementet.

For oppsett, lokal feilsøking og distribusjonsinstruksjoner, se Use Functions in Fabric Apps.

Utviklingsarbeidsflyt

En typisk utviklingssyklus følger dette mønsteret:

  1. Definer eller modifiser datamodeller – Legg til eller oppdater TypeScript-klasser med dekoratorer
  2. Test lokalt med ekstern backend - Kjør npm run dev for å teste endringene i frontend-koden mot app-backend i Fabric.
  3. Deploy to Fabric - Kjør npx rayfin up for å distribuere til den administrerte Fabric-tjenesten og anvende skjemaendringene dine.

Endringer i TypeScript-modellene dine sprer seg automatisk gjennom hele stakken — fra databaseskjema til API-endepunkter til klienttyper.

Authorization

Tillatelser defineres sammen med datamodellene dine ved bruk av decoratoren @role :

@entity()
@role('authenticated', ['create', 'read', 'update', 'delete'], {
  policy: (claims, item) => claims.sub.eq(item.userId)
})
export class UserDocument {
  @uuid() id!: string;
  @text() userId!: string;
  @text() content!: string;
}

Denne tilnærmingen sikrer:

  • Sikkerhetsregler ligger ved siden av dataene de beskytter
  • Typesikre policyuttrykk fanger feil ved kompilering
  • Refaktorering av entitetsfelt oppdaterer automatisk tillatelsessjekker