Middlewares
Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →
Puedes agregar middlewares a un router completo usando el método middleware(). Los middlewares envolverán la invocación del procedimiento y deben pasar su valor de retorno.
Autorización
En el ejemplo siguiente, cualquier llamada a admin.* asegurará que el usuario sea un "admin" antes de ejecutar cualquier query o mutation.
tstrpc.router<Context>().query('foo', {resolve() {return 'bar';},}).merge('admin.',trpc.router<Context>().middleware(async (opts) => {if (!opts.ctx.user?.isAdmin) {throw new TRPCError({ code: 'UNAUTHORIZED' });}return opts.next();}).query('secretPlace', {resolve() {return 'a key';},}),);
tstrpc.router<Context>().query('foo', {resolve() {return 'bar';},}).merge('admin.',trpc.router<Context>().middleware(async (opts) => {if (!opts.ctx.user?.isAdmin) {throw new TRPCError({ code: 'UNAUTHORIZED' });}return opts.next();}).query('secretPlace', {resolve() {return 'a key';},}),);
Consulta Manejo de errores para aprender más sobre el TRPCError lanzado en el ejemplo anterior.
Registro (Logging)
En el ejemplo siguiente, los tiempos de las consultas se registran automáticamente.
tstrpc.router<Context>().middleware(async ({ path, type, next }) => {const start = Date.now();const result = await next();const durationMs = Date.now() - start;result.ok? logMock('OK request timing:', { path, type, durationMs }): logMock('Non-OK request timing', { path, type, durationMs });return result;}).query('foo', {resolve() {return 'bar';},}).query('abc', {resolve() {return 'def';},});
tstrpc.router<Context>().middleware(async ({ path, type, next }) => {const start = Date.now();const result = await next();const durationMs = Date.now() - start;result.ok? logMock('OK request timing:', { path, type, durationMs }): logMock('Non-OK request timing', { path, type, durationMs });return result;}).query('foo', {resolve() {return 'bar';},}).query('abc', {resolve() {return 'def';},});
Cambio de contexto
Un middleware puede reemplazar el contexto del router, y los procedimientos posteriores recibirán el nuevo valor de contexto:
tsinterface Context {// user is nullableuser?: {id: string;};}trpc.router<Context>().middleware((opts) => {if (!opts.ctx.user) {throw new TRPCError({ code: 'UNAUTHORIZED' });}return opts.next({ctx: {...opts.ctx,user: opts.ctx.user, // user value is known to be non-null now},});}).query('userId', {async resolve({ ctx }) {return ctx.user.id;},});
tsinterface Context {// user is nullableuser?: {id: string;};}trpc.router<Context>().middleware((opts) => {if (!opts.ctx.user) {throw new TRPCError({ code: 'UNAUTHORIZED' });}return opts.next({ctx: {...opts.ctx,user: opts.ctx.user, // user value is known to be non-null now},});}).query('userId', {async resolve({ ctx }) {return ctx.user.id;},});
Ayudante createProtectedRouter()
Este ayudante se puede usar en cualquier parte del árbol de tu aplicación para exigir que los procedimientos posteriores estén autorizados.
server/createRouter.tstsximport * as trpc from '@trpc/server';import { Context } from './context';export function createProtectedRouter() {return trpc.router<Context>().middleware((opts) => {if (!opts.ctx.user) {throw new trpc.TRPCError({ code: 'UNAUTHORIZED' });}return opts.next({ctx: {...opts.ctx,// infers that `user` is non-nullable to downstream proceduresuser: opts.ctx.user,},});});}
server/createRouter.tstsximport * as trpc from '@trpc/server';import { Context } from './context';export function createProtectedRouter() {return trpc.router<Context>().middleware((opts) => {if (!opts.ctx.user) {throw new trpc.TRPCError({ code: 'UNAUTHORIZED' });}return opts.next({ctx: {...opts.ctx,// infers that `user` is non-nullable to downstream proceduresuser: opts.ctx.user,},});});}
Entrada sin procesar
Un middleware puede acceder a la entrada sin procesar que se pasará a un procedimiento. Esto es útil para autenticación u otro preprocesamiento que requiera acceso a la entrada del procedimiento, y resulta especialmente valioso cuando se combina con Cambio de contexto.
El rawInput pasado a un middleware aún no ha sido validado por el esquema/validador input de un procedimiento, ¡así que ten cuidado al usarlo! Por esta razón, rawInput tiene tipo unknown. Para más información, consulta #1059.
tsconst inputSchema = z.object({ userId: z.string() });trpc.router<Context>().middleware(async ({ next, rawInput, ctx }) => {const result = inputSchema.safeParse(rawInput);if (!result.success) throw new TRPCError({ code: 'BAD_REQUEST' });const { userId } = result.data;// Check user id authreturn next({ ctx: { ...ctx, userId } });}).query('userId', {input: inputSchema,resolve({ ctx }) {return ctx.userId;},});
tsconst inputSchema = z.object({ userId: z.string() });trpc.router<Context>().middleware(async ({ next, rawInput, ctx }) => {const result = inputSchema.safeParse(rawInput);if (!result.success) throw new TRPCError({ code: 'BAD_REQUEST' });const { userId } = result.data;// Check user id authreturn next({ ctx: { ...ctx, userId } });}).query('userId', {input: inputSchema,resolve({ ctx }) {return ctx.userId;},});