Typesikre API'er fra frontend til backend med tRPC · Lektion

Tilpassede middleware-kæder

Opbyg tilpasset middleware til logning, rate limiting eller autorisation, og kæd dem sammen.

Lektion 3 af 411 trin

Tilpassede middleware-kæder er en gratis Typesikre API'er fra frontend til backend med tRPC-lektion på CoddyKit. Dette er lektion 3 af 4. Du kan læse alle 3 lektioner i dette læringsspor gratis i deres fulde længde — derefter låser CoddyKit PRO alle lektioner op samt praktiske øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Den er en del af læringsforløbet i Typesikre API'er fra frontend til backend med tRPC, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Typesikre API'er fra frontend til backend med tRPC-kurset indeholder 4 lektioner i alt.

Kæd flere middleware sammen

I tRPC giver middleware dig mulighed for at køre logik, før din procedure udføres. Hvad gør du, hvis du har brug for flere kontroller, f.eks. logning, godkendelse og validering, for ét API-kald?

Det er her, middleware-kæder er nyttige! De gør det muligt at stable flere middleware-funktioner, som udføres én efter én.

Fordele ved kædning

Kædning af middleware har flere fordele:

  • Modularitet: Hvert middleware fokuserer på ét ansvar, f.eks. logning eller godkendelse.
  • Genbrug: Opret generisk middleware, der kan anvendes på forskellige procedurer eller routere.
  • Udførelsesrækkefølge: Styr den præcise rækkefølge af handlinger, før din primære procedurlogik kører.
  • Tidlig afslutning: Et middleware kan stoppe kæden tidligt, hvis en betingelse ikke er opfyldt, f.eks. ved uautoriseret adgang.

Sådan fungerer `next()`

Husk, at tRPC-middleware modtager en next-funktion. Når du kalder next(), gives kontrollen videre til det næste middleware i kæden eller til den faktiske procedurehandler, hvis dette er det sidste middleware.

Hvis et middleware ikke kalder next(), stopper kæden, og procedurehandleren bliver ikke udført. Det er afgørende ved kontroller som godkendelse!

Først: Middleware til logning

Lad os oprette et enkelt middleware til logning. Det logger, hvornår en anmodning starter, og hvor lang tid den tog. Det er et almindeligt mønster til overvågning.

Bemærk, at der ventes på next() for at sikre, at proceduren og efterfølgende middleware er færdige, før varigheden 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!")
});

Dernæst: Middleware til godkendelse

Dernæst opbygger vi et middleware til godkendelse. Dette middleware kontrollerer, om en bruger er logget ind, altså om ctx.userId findes. Hvis ikke, kaster det en fejl og stopper dermed proceduren.

Husk, at ctx-objektet (konteksten) sendes til middleware, så det kan få adgang til data, der er specifikke for anmodningen.

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}!`)
});

Opbygning af en middleware-kæde

Nu kombinerer vi vores logMiddleware- og isAuthenticated-middleware. Rækkefølgen er vigtig: Logningen skal ske først, derefter godkendelsen.

Vi bruger blot .use() flere gange. tRPC udfører dem i den rækkefølge, de er defineret i.

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}!`)
});

Udførelsesrækkefølge

Når en anmodning rammer protectedData:

  1. logMiddleware køres først.
  2. Hvis logMiddleware kalder next(), køres isAuthenticated.
  3. Hvis isAuthenticated kalder next(), køres den faktiske query-procedurehandler.
  4. Hvis et middleware kaster en fejl, f.eks. isAuthenticated, stopper kæden med det samme, og fejlen returneres.

Dynamisk middleware

Hvad gør du, hvis du har brug for forskellige autorisationsniveauer? Du kan oprette en funktion, der returnerer et middleware, så du kan konfigurere det dynamisk.

Dette mønster kaldes en middleware-builder og er effektivt til at oprette fleksibelt og genanvendeligt 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!")
});

Kædning af dynamisk middleware

Du kan kombinere statisk middleware, f.eks. vores logger, med dynamiske middleware-buildere, f.eks. vores rollekontrol, i den samme kæde.

Det giver meget fleksible og sikre API-endepunkter, hvor specifik logik kan anvendes baseret på konfiguration eller værdier under kørsel.

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.")
});

Logikken i en middleware-kæde

Se på følgende definition af en tRPC-procedure:

// 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 der kommer en anmodning med ctx.userId = null, hvad sker der så?

Opsummering af kæder

Godt gået! Du har lært at opbygge og kæde flere brugerdefinerede middleware sammen i tRPC.

  • Middleware-kæder gør det muligt at anvende flere lag logik, f.eks. logning, godkendelse og validering, før en procedure udføres.
  • Metoden .use() bruges til at tilføje middleware, og de køres i den rækkefølge, de er defineret i.
  • Funktionen next() er afgørende for at føre kontrollen videre gennem kæden.
  • Middleware-buildere kan oprette dynamisk og konfigurerbart middleware, der kan genbruges i højere grad.

Dette effektive mønster hjælper med at holde din tRPC-API-kode ren, modulær og robust!

Gratis at komme i gang

Lær Typesikre API'er fra frontend til backend med tRPC med en AI-underviser — gratis

Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.

Kurser
10
Lektioner
40

Ofte stillede spørgsmål

Er lektionen “Tilpassede middleware-kæder” gratis?

Ja — alle 3 lektioner i læringssporet Typesikre API'er fra frontend til backend med tRPC, inklusive “Tilpassede middleware-kæder”, kan læses gratis i deres fulde længde her på webstedet. Derefter låser CoddyKit PRO alle lektioner op samt interaktive øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Typesikre API'er fra frontend til backend med tRPC-kurset indeholder 4 lektioner i alt.

Hvad lærer jeg i “Tilpassede middleware-kæder”?

Opbyg tilpasset middleware til logning, rate limiting eller autorisation, og kæd dem sammen. Du øver dig i Typesikre API'er fra frontend til backend med tRPC med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.

Skal jeg have erfaring for at begynde på Typesikre API'er fra frontend til backend med tRPC?

Der kræves ingen tidligere erfaring. Typesikre API'er fra frontend til backend med tRPC på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 3 af 4.

Hvor lang tid tager lektionen “Tilpassede middleware-kæder”?

De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.

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

Ja. Alle Typesikre API'er fra frontend til backend med tRPC-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.

Alle lektioner i dette kursus

  1. Oprettelse af tRPC-context
  2. Godkendelses-middleware
  3. Tilpassede middleware-kæder
  4. Middleware til logging og måling af ydeevne
← Tilbage til Typesikre API'er fra frontend til backend med tRPC