Typesikre API-er fra frontend til backend med tRPC · leksjon

Egendefinerte mellomvarekjeder

Bygg egendefinert mellomvare for logging, hastighetsbegrensning eller autorisasjon, og kjed dem sammen.

Leksjon 3 av 411 trinn

Egendefinerte mellomvarekjeder er en gratis leksjon i Typesikre API-er fra frontend til backend med tRPC på CoddyKit. Dette er leksjon 3 av 4. Du kan lese valgfritt 3 leksjoner fra denne læringsstien gratis i sin helhet – deretter låser CoddyKit PRO opp alle leksjoner, samt praktisk øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i Typesikre API-er fra frontend til backend med tRPC, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i Typesikre API-er fra frontend til backend med tRPC inneholder totalt 4 leksjoner.

Lenke sammen flere middleware-komponenter

I tRPC lar middleware deg kjøre logikk før prosedyren utføres. Hva om du trenger flere kontroller, som logging, autentisering og validering, for ett enkelt API-kall?

Det er her middleware-kjeder kommer til nytte! De lar deg stable flere middleware-funksjoner, som utføres én etter én.

Fordeler ved å lenke sammen middleware

Det gir flere fordeler å lenke sammen middleware-komponenter:

  • Modularitet: Hver middleware-komponent fokuserer på ett enkelt ansvarsområde, for eksempel logging eller autentisering.
  • Gjenbruk: Opprett generell middleware som kan brukes på ulike prosedyrer eller rutere.
  • Utførelsesrekkefølge: Styr den nøyaktige rekkefølgen på operasjonene før hovedlogikken i prosedyren kjøres.
  • Tidlig avslutning: En middleware-komponent kan stoppe kjeden tidlig hvis en betingelse ikke er oppfylt, for eksempel ved uautorisert tilgang.

Slik fungerer `next()`

Husk at tRPC-middleware mottar en next-funksjon. Når du kaller next(), overlater du kontrollen til neste middleware-komponent i kjeden, eller til den faktiske prosedyrehåndtereren hvis dette er den siste middleware-komponenten.

Hvis en middleware-komponent ikke kaller next(), stopper kjeden, og prosedyrehåndtereren blir ikke kjørt. Dette er avgjørende for kontroller som autentisering!

Først: Logging-middleware

La oss opprette en enkel logging-middleware. Den skal logge når en forespørsel starter, og hvor lang tid den tok. Dette er et vanlig mønster for overvåking.

Legg merke til at next() awaites for å sikre at prosedyren (og påfølgende middleware-komponenter) er ferdig før varigheten logges.

type Context = { userId: string | null };
const trpc = {
  middleware: (handler: any) => handler,
  procedure: {
    use: (mw: any) => ({
      query: (f: any) => f,
      mutation: (f: any) => f
    }),
    query: (f: any) => f,
    mutation: (f: any) => f
  },
  router: (cfg: any) => cfg,
};

const logMiddleware = trpc.middleware(async ({ path, type, next }) => {
  console.log(`[${type}] Request to ${path} started.`);
  const start = Date.now();
  const result = await next();
  const durationMs = Date.now() - start;
  console.log(`[${type}] Request to ${path} finished in ${durationMs}ms.`);
  return result;
});

const appRouter = trpc.router({
  example: trpc.procedure
    .use(logMiddleware)
    .query(() => "Data fetched!")
});

Deretter: Autentiserings-middleware

Deretter bygger vi en autentiserings-middleware. Denne middleware-komponenten kontrollerer om en bruker er logget inn, altså om ctx.userId finnes. Hvis ikke, kaster den en feil og stopper dermed prosedyren.

Husk at ctx-objektet (konteksten) sendes til middleware-komponenter, slik at de får tilgang til forespørselsspesifikke data.

type Context = { userId: string | null };
const trpc = {
  middleware: (handler: any) => handler,
  procedure: {
    use: (mw: any) => ({
      query: (f: any) => f,
      mutation: (f: any) => f
    }),
    query: (f: any) => f,
    mutation: (f: any) => f
  },
  router: (cfg: any) => cfg,
};

const isAuthenticated = trpc.middleware(async ({ ctx, next }) => {
  if (!ctx.userId) {
    throw new Error("UNAUTHORIZED: Please log in.");
  }
  return next();
});

const appRouter = trpc.router({
  protected: trpc.procedure
    .use(isAuthenticated)
    .query(({ ctx }) => `Welcome, user ${ctx.userId}!`)
});

Bygge en middleware-kjede

Nå kombinerer vi logMiddleware og isAuthenticated-middleware. Rekkefølgen er viktig: Logging skal skje først, deretter autentisering.

Vi bruker ganske enkelt .use() flere ganger. tRPC utfører dem i den rekkefølgen de er definert.

type Context = { userId: string | null };
const trpc = {
  middleware: (handler: any) => handler,
  procedure: {
    use: (mw: any) => ({
      query: (f: any) => f,
      mutation: (f: any) => f
    }),
    query: (f: any) => f,
    mutation: (f: any) => f
  },
  router: (cfg: any) => cfg,
};

const logMiddleware = trpc.middleware(async ({ path, type, next }) => {
  console.log(`[${type}] Request to ${path} started.`);
  const start = Date.now();
  const result = await next();
  const durationMs = Date.now() - start;
  console.log(`[${type}] Request to ${path} finished in ${durationMs}ms.`);
  return result;
});

const isAuthenticated = trpc.middleware(async ({ ctx, next }) => {
  if (!ctx.userId) {
    throw new Error("UNAUTHORIZED: Please log in.");
  }
  return next();
});

const appRouter = trpc.router({
  protectedData: trpc.procedure
    .use(logMiddleware)
    .use(isAuthenticated)
    .query(({ ctx }) => `Secret data for ${ctx.userId}!`)
});

Utførelsesrekkefølge

Når en forespørsel treffer protectedData:

  1. logMiddleware kjører først.
  2. Hvis logMiddleware kaller next(), kjører deretter isAuthenticated.
  3. Hvis isAuthenticated kaller next(), kjører den faktiske query-prosedyrehåndtereren.
  4. Hvis en middleware-komponent kaster en feil, som isAuthenticated kan gjøre, stopper kjeden umiddelbart, og feilen returneres.

Dynamisk middleware

Hva om du trenger ulike autoriseringsnivåer? Du kan opprette en funksjon som returnerer en middleware-komponent, slik at konfigurasjonen kan være dynamisk.

Dette mønsteret kalles en middleware-bygger og er nyttig når du skal opprette fleksibel og gjenbrukbar middleware.

type Context = { userId: string | null; userRole: string | null };
const trpc = {
  middleware: (handler: any) => handler,
  procedure: {
    use: (mw: any) => ({
      query: (f: any) => f,
      mutation: (f: any) => f
    }),
    query: (f: any) => f,
    mutation: (f: any) => f
  },
  router: (cfg: any) => cfg,
};

const hasRole = (requiredRole: string) => {
  return trpc.middleware(async ({ ctx, next }) => {
    if (!ctx.userRole || ctx.userRole !== requiredRole) {
      throw new Error(`FORBIDDEN: ${requiredRole} role required.`);
    }
    return next();
  });
};

const appRouter = trpc.router({
  adminPanel: trpc.procedure
    .use(hasRole("admin"))
    .query(() => "Welcome, admin!")
});

Lenke sammen dynamisk middleware

Du kan kombinere statisk middleware, som loggeren vår, med dynamiske middleware-byggere, som rolleoppslaget vårt, i den samme kjeden.

Dette gir svært fleksible og sikre API-endepunkter, der spesifikk logikk kan brukes basert på konfigurasjon eller verdier fra kjøring.

type Context = { userId: string | null; userRole: string | null };
const trpc = {
  middleware: (handler: any) => handler,
  procedure: {
    use: (mw: any) => ({
      query: (f: any) => f,
      mutation: (f: any) => f
    }),
    query: (f: any) => f,
    mutation: (f: any) => f
  },
  router: (cfg: any) => cfg,
};

const logMiddleware = trpc.middleware(async ({ path, type, next }) => {
  console.log(`[${type}] Request to ${path} started.`);
  const start = Date.now();
  const result = await next();
  const durationMs = Date.now() - start;
  console.log(`[${type}] Request to ${path} finished in ${durationMs}ms.`);
  return result;
});

const hasRole = (requiredRole: string) => {
  return trpc.middleware(async ({ ctx, next }) => {
    if (!ctx.userRole || ctx.userRole !== requiredRole) {
      throw new Error(`FORBIDDEN: ${requiredRole} role required.`);
    }
    return next();
  });
};

const appRouter = trpc.router({
  adminReport: trpc.procedure
    .use(logMiddleware)
    .use(hasRole("admin"))
    .query(() => "Sensitive admin report data.")
});

Logikk i middleware-kjeder

Se på følgende definisjon av en tRPC-prosedyre:

// Assume logMiddleware and authMiddleware are defined
// authMiddleware throws if ctx.userId is null
// logMiddleware always calls next()
const myProcedure = trpc.procedure
  .use(logMiddleware)
  .use(authMiddleware)
  .query(({ ctx }) => `Hello ${ctx.userId}`);

Hvis en forespørsel kommer inn med ctx.userId = null, hva skjer da?

Oppsummering av middleware-kjeder

Godt jobbet! Du har lært hvordan du bygger og lenker sammen flere egendefinerte middleware-komponenter i tRPC.

  • Middleware-kjeder lar deg bruke flere lag med logikk, som logging, autentisering og validering, før en prosedyre utføres.
  • Metoden .use() brukes til å legge til middleware-komponenter, og de kjøres i den rekkefølgen de er definert.
  • Funksjonen next() er avgjørende for å føre kontrollen videre i kjeden.
  • Middleware-byggere kan opprette dynamisk og konfigurerbar middleware som gir bedre gjenbruk.

Dette kraftige mønsteret bidrar til å holde tRPC API-koden ryddig, modulær og robust!

Gratis å komme i gang

Lær deg Typesikre API-er fra frontend til backend med tRPC med en AI-veileder – gratis

Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.

Kurs
10
Leksjoner
40

Ofte stilte spørsmål

Er leksjonen «Egendefinerte mellomvarekjeder» gratis?

Ja – du kan lese valgfritt 3 av leksjonene i læringsstien Typesikre API-er fra frontend til backend med tRPC, inkludert «Egendefinerte mellomvarekjeder», gratis i sin helhet her på nettet. Deretter låser CoddyKit PRO opp alle leksjoner, samt interaktiv øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Kurset i Typesikre API-er fra frontend til backend med tRPC inneholder totalt 4 leksjoner.

Hva lærer jeg i «Egendefinerte mellomvarekjeder»?

Bygg egendefinert mellomvare for logging, hastighetsbegrensning eller autorisasjon, og kjed dem sammen. Du øver på Typesikre API-er fra frontend til backend med tRPC med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.

Trenger jeg erfaring for å begynne med Typesikre API-er fra frontend til backend med tRPC?

Ingen tidligere erfaring er nødvendig. Typesikre API-er fra frontend til backend med tRPC på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 3 av 4.

Hvor lang tid tar leksjonen «Egendefinerte mellomvarekjeder»?

De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.

Kan jeg skrive og kjøre kode i denne Typesikre API-er fra frontend til backend med tRPC-leksjonen?

Ja. Alle Typesikre API-er fra frontend til backend med tRPC-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.

Alle leksjonene i dette kurset

  1. Opprette tRPC-kontekst
  2. Autentiseringsmellomvare
  3. Egendefinerte mellomvarekjeder
  4. Middleware for logging og ytelsesmåling
← Tilbake til Typesikre API-er fra frontend til backend med tRPC