Context
Denna sida har översatts av PageTurner AI (beta). Inte officiellt godkänd av projektet. Hittade du ett fel? Rapportera problem →
Din context innehåller data som alla dina tRPC-procedurer kommer att ha tillgång till, och är ett utmärkt ställe att lägga saker som databasanslutningar eller autentiseringsinformation.
Att sätta upp contexten görs i två steg: först definierar du typen under initialiseringen och sedan skapar du runtime-contexten för varje förfrågan.
Definiera context-typen
När du initierar tRPC med initTRPC bör du kedja .context<TContext>() till initTRPC-byggarfunktionen innan du anropar .create(). Typen TContext kan antingen härledas från en funktions returtyp eller definieras explicit.
Detta säkerställer att din context är korrekt typad i dina procedurer och middleware.
tsimport {initTRPC } from '@trpc/server';import type {CreateNextContextOptions } from '@trpc/server/adapters/next';import {getSession } from 'next-auth/react';export constcreateContext = async (opts :CreateNextContextOptions ) => {constsession = awaitgetSession ({req :opts .req });return {session ,};};constt1 =initTRPC .context <typeofcreateContext >().create ();t1 .procedure .use (({ctx }) => { ... });typeContext =Awaited <ReturnType <typeofcreateContext >>;constt2 =initTRPC .context <Context >().create ();t2 .procedure .use (({ctx }) => { ... });
tsimport {initTRPC } from '@trpc/server';import type {CreateNextContextOptions } from '@trpc/server/adapters/next';import {getSession } from 'next-auth/react';export constcreateContext = async (opts :CreateNextContextOptions ) => {constsession = awaitgetSession ({req :opts .req });return {session ,};};constt1 =initTRPC .context <typeofcreateContext >().create ();t1 .procedure .use (({ctx }) => { ... });typeContext =Awaited <ReturnType <typeofcreateContext >>;constt2 =initTRPC .context <Context >().create ();t2 .procedure .use (({ctx }) => { ... });
Skapa context
Funktionen createContext() måste skickas till handlern som monterar din appRouter, vilket kan ske via HTTP, ett server-side call eller våra server-side helpers.
createContext() anropas för varje tRPC-invokering, så batchade förfrågningar delar samma context.
ts// 1. HTTP requestimport { createHTTPHandler } from '@trpc/server/adapters/standalone';import { createContext } from './context';import { createCaller } from './router';const handler = createHTTPHandler({router: appRouter,createContext,});
ts// 1. HTTP requestimport { createHTTPHandler } from '@trpc/server/adapters/standalone';import { createContext } from './context';import { createCaller } from './router';const handler = createHTTPHandler({router: appRouter,createContext,});
ts// 2. Server-side callimport { createContext } from './context';import { createCaller } from './router';const caller = createCaller(await createContext());
ts// 2. Server-side callimport { createContext } from './context';import { createCaller } from './router';const caller = createCaller(await createContext());
ts// 3. servers-side helpersimport { createServerSideHelpers } from '@trpc/react-query/server';import { createContext } from './context';import { appRouter } from './router';const helpers = createServerSideHelpers({router: appRouter,ctx: await createContext(),});
ts// 3. servers-side helpersimport { createServerSideHelpers } from '@trpc/react-query/server';import { createContext } from './context';import { appRouter } from './router';const helpers = createServerSideHelpers({router: appRouter,ctx: await createContext(),});
Exempelkod
tsx// -------------------------------------------------// @filename: context.ts// -------------------------------------------------import type {CreateNextContextOptions } from '@trpc/server/adapters/next';import {getSession } from 'next-auth/react';/*** Creates context for an incoming request* @see https://trpc.io/docs/context*/export async functioncreateContext (opts :CreateNextContextOptions ) {constsession = awaitgetSession ({req :opts .req });return {session ,};}export typeContext =Awaited <ReturnType <typeofcreateContext >>;// -------------------------------------------------// @filename: trpc.ts// -------------------------------------------------import {initTRPC ,TRPCError } from '@trpc/server';import {Context } from './context';constt =initTRPC .context <Context >().create ();export constrouter =t .router ;/*** Unprotected procedure*/export constpublicProcedure =t .procedure ;/*** Protected procedure*/export constprotectedProcedure =t .procedure .use (functionisAuthed (opts ) {if (!opts .ctx .session ?.user ?.throw newTRPCError ({code : 'UNAUTHORIZED',});}returnopts .next ({ctx : {// Infers the `session` as non-nullablesession :opts .ctx .session ,},});});
tsx// -------------------------------------------------// @filename: context.ts// -------------------------------------------------import type {CreateNextContextOptions } from '@trpc/server/adapters/next';import {getSession } from 'next-auth/react';/*** Creates context for an incoming request* @see https://trpc.io/docs/context*/export async functioncreateContext (opts :CreateNextContextOptions ) {constsession = awaitgetSession ({req :opts .req });return {session ,};}export typeContext =Awaited <ReturnType <typeofcreateContext >>;// -------------------------------------------------// @filename: trpc.ts// -------------------------------------------------import {initTRPC ,TRPCError } from '@trpc/server';import {Context } from './context';constt =initTRPC .context <Context >().create ();export constrouter =t .router ;/*** Unprotected procedure*/export constpublicProcedure =t .procedure ;/*** Protected procedure*/export constprotectedProcedure =t .procedure .use (functionisAuthed (opts ) {if (!opts .ctx .session ?.user ?.throw newTRPCError ({code : 'UNAUTHORIZED',});}returnopts .next ({ctx : {// Infers the `session` as non-nullablesession :opts .ctx .session ,},});});
Inner och outer context
I vissa scenarion kan det vara meningsfullt att dela upp din context i "inner"- och "outer"-funktioner.
Inner context är där du definierar context som inte beror på förfrågan, t.ex. din databasanslutning. Du kan använda denna funktion för integrationstestning eller server-side helpers, där du inte har ett request-objekt. Allt som definieras här kommer alltid att vara tillgängligt i dina procedurer.
Outer context är där du definierar context som beror på förfrågan, t.ex. för användarsession. Allt som definieras här är endast tillgängligt för procedurer som anropas via HTTP.
Exempel på inner & outer context
tsimport type { CreateNextContextOptions } from '@trpc/server/adapters/next';import { getSessionFromCookie, type Session } from './auth';/*** Defines your inner context shape.* Add fields here that the inner context brings.*/interface CreateInnerContextOptions extends Partial<CreateNextContextOptions> {session: Session | null;}/*** Inner context. Will always be available in your procedures, in contrast to the outer context.** Also useful for:* - testing, so you don't have to mock Next.js' `req`/`res`* - tRPC's `createServerSideHelpers` where we don't have `req`/`res`** @see https://trpc.io/docs/context#inner-and-outer-context*/export async function createContextInner(opts?: CreateInnerContextOptions) {return {prisma,session: opts.session,};}/*** Outer context. Used in the routers and will e.g. bring `req` & `res` to the context as "not `undefined`".** @see https://trpc.io/docs/context#inner-and-outer-context*/export async function createContext(opts: CreateNextContextOptions) {const session = getSessionFromCookie(opts.req);const contextInner = await createContextInner({ session });return {...contextInner,req: opts.req,res: opts.res,};}export type Context = Awaited<ReturnType<typeof createContextInner>>;// The usage in your router is the same as the example above.
tsimport type { CreateNextContextOptions } from '@trpc/server/adapters/next';import { getSessionFromCookie, type Session } from './auth';/*** Defines your inner context shape.* Add fields here that the inner context brings.*/interface CreateInnerContextOptions extends Partial<CreateNextContextOptions> {session: Session | null;}/*** Inner context. Will always be available in your procedures, in contrast to the outer context.** Also useful for:* - testing, so you don't have to mock Next.js' `req`/`res`* - tRPC's `createServerSideHelpers` where we don't have `req`/`res`** @see https://trpc.io/docs/context#inner-and-outer-context*/export async function createContextInner(opts?: CreateInnerContextOptions) {return {prisma,session: opts.session,};}/*** Outer context. Used in the routers and will e.g. bring `req` & `res` to the context as "not `undefined`".** @see https://trpc.io/docs/context#inner-and-outer-context*/export async function createContext(opts: CreateNextContextOptions) {const session = getSessionFromCookie(opts.req);const contextInner = await createContextInner({ session });return {...contextInner,req: opts.req,res: opts.res,};}export type Context = Awaited<ReturnType<typeof createContextInner>>;// The usage in your router is the same as the example above.
Det är viktigt att härleda din Context från inner-contexten, eftersom endast det som definieras där verkligen alltid är tillgängligt i dina procedurer.
Om du inte vill kontrollera om req eller res är undefined i dina procedurer hela tiden, kan du bygga en liten återanvändbar procedur för det:
tsexport const apiProcedure = publicProcedure.use((opts) => {if (!opts.ctx.req || !opts.ctx.res) {throw new Error('You are missing `req` or `res` in your call.');}return opts.next({ctx: {// We overwrite the context with the truthy `req` & `res`, which will also overwrite the types used in your procedure.req: opts.ctx.req,res: opts.ctx.res,},});});
tsexport const apiProcedure = publicProcedure.use((opts) => {if (!opts.ctx.req || !opts.ctx.res) {throw new Error('You are missing `req` or `res` in your call.');}return opts.next({ctx: {// We overwrite the context with the truthy `req` & `res`, which will also overwrite the types used in your procedure.req: opts.ctx.req,res: opts.ctx.res,},});});