TRPC Zod Procedure Input Validation

Define typed RPC procedures with tRPC and Zod input schemas, sharing inferred types end to end without a schema registry or codegen step.

TypescriptData Fetching

Code

snippet
import { initTRPC } from '@trpc/server';
import { z } from 'zod';
import { createHTTPContext } from './context';

const t = initTRPC.context<typeof createHTTPContext>().create();

const publicProcedure = t.procedure;
const router = t.router;

const postRouter = router({
  byId: publicProcedure
    .input(z.object({ id: z.string().uuid() }))
    .query(async ({ input, ctx }) => {
      return ctx.db.posts.find((p) => p.id === input.id) ?? null;
    }),

  list: publicProcedure
    .input(z.object({
      page: z.number().int().min(1).default(1),
      limit: z.number().int().min(1).max(50).default(20),
    }))
    .query(async ({ input, ctx }) => {
      const start = (input.page - 1) * input.limit;
      return ctx.db.posts.slice(start, start + input.limit);
    }),

  create: publicProcedure
    .input(z.object({
      title: z.string().min(3).max(120),
      body: z.string().min(1),
    }))
    .mutation(async ({ input, ctx }) => {
      const post = { id: crypto.randomUUID(), ...input };
      ctx.db.posts.push(post);
      return post;
    }),
});

export const appRouter = router({ posts: postRouter });
export type AppRouter = typeof appRouter;