Validerare för indata och utdata
Denna sida har översatts av PageTurner AI (beta). Inte officiellt godkänd av projektet. Hittade du ett fel? Rapportera problem →
tRPC-procedurer kan definiera valideringslogik för sina indata och/eller utdata, och validerare används också för att härleda typerna för indata och utdata. Vi har förstaklassstöd för många populära validerare, och du kan integrera validerare som vi inte stöder direkt.
Validerare för indata
Genom att definiera en indatavaliderare kan tRPC kontrollera att ett procedureanrop är korrekt och returnera ett valideringsfel om det inte är det.
För att konfigurera en indatavaliderare, använd metoden procedure.input():
ts// @target: esnextimport { initTRPC } from '@trpc/server';// ---cut---// Our examples use Zod by default, but usage with other libraries is identicalimport { z } from 'zod';export const t = initTRPC.create();const publicProcedure = t.procedure;export const appRouter = t.router({hello: publicProcedure.input(z.object({name: z.string(),}),).query((opts) => {const name = opts.input.name;// ^?return {greeting: `Hello ${opts.input.name}`,};}),});
ts// @target: esnextimport { initTRPC } from '@trpc/server';// ---cut---// Our examples use Zod by default, but usage with other libraries is identicalimport { z } from 'zod';export const t = initTRPC.create();const publicProcedure = t.procedure;export const appRouter = t.router({hello: publicProcedure.input(z.object({name: z.string(),}),).query((opts) => {const name = opts.input.name;// ^?return {greeting: `Hello ${opts.input.name}`,};}),});
Sammanfogning av indata
.input() kan staplas för att bygga mer komplexa typer, vilket är särskilt användbart när du vill utnyttja gemensam indata för en samling procedurer i en middleware.
ts// @target: esnextimport { initTRPC, TRPCError } from '@trpc/server';import { z } from 'zod';export const t = initTRPC.create();// ---cut---const baseProcedure = t.procedure.input(z.object({ townName: z.string() })).use((opts) => {const input = opts.input;// ^?console.log(`Handling request with user from: ${input.townName}`);return opts.next();});export const appRouter = t.router({hello: baseProcedure.input(z.object({name: z.string(),}),).query((opts) => {const input = opts.input;// ^?return {greeting: `Hello ${input.name}, my friend from ${input.townName}`,};}),});
ts// @target: esnextimport { initTRPC, TRPCError } from '@trpc/server';import { z } from 'zod';export const t = initTRPC.create();// ---cut---const baseProcedure = t.procedure.input(z.object({ townName: z.string() })).use((opts) => {const input = opts.input;// ^?console.log(`Handling request with user from: ${input.townName}`);return opts.next();});export const appRouter = t.router({hello: baseProcedure.input(z.object({name: z.string(),}),).query((opts) => {const input = opts.input;// ^?return {greeting: `Hello ${input.name}, my friend from ${input.townName}`,};}),});
Validerare för utdata
Validering av utdata är inte alltid lika viktigt som att definiera indata, eftersom tRPC ger dig automatisk typsäkerhet genom att härleda returtypen för dina procedurer. Några skäl att definiera en utdatavaliderare inkluderar:
-
Kontrollera att data som returneras från ej betrodda källor är korrekt
-
Säkerställa att du inte returnerar mer data till klienten än nödvändigt
Om utdatavalidering misslyckas kommer servern att svara med ett INTERNAL_SERVER_ERROR.
ts// @target: esnextimport { initTRPC } from '@trpc/server';// @noErrors// ---cut---import { z } from 'zod';export const t = initTRPC.create();const publicProcedure = t.procedure;export const appRouter = t.router({hello: publicProcedure.output(z.object({greeting: z.string(),}),).query((opts) => {return {gre,// ^|};}),});
ts// @target: esnextimport { initTRPC } from '@trpc/server';// @noErrors// ---cut---import { z } from 'zod';export const t = initTRPC.create();const publicProcedure = t.procedure;export const appRouter = t.router({hello: publicProcedure.output(z.object({greeting: z.string(),}),).query((opts) => {return {gre,// ^|};}),});
Den mest grundläggande valideraren: en funktion
Du kan definiera en validerare utan några tredjepartsberoenden, med en funktion.
Vi rekommenderar inte att skapa en anpassad validerare om du inte har ett specifikt behov, men det är viktigt att förstå att det inte finns någon magi här - det är bara TypeScript!
I de flesta fall rekommenderar vi att du använder ett valideringsbibliotek
tsimport { initTRPC } from '@trpc/server';export const t = initTRPC.create();const publicProcedure = t.procedure;export const appRouter = t.router({hello: publicProcedure.input((value): string => {if (typeof value === 'string') {return value;}throw new Error('Input is not a string');}).output((value): string => {if (typeof value === 'string') {return value;}throw new Error('Output is not a string');}).query((opts) => {const { input } = opts;// ^?return `hello ${input}`;}),});export type AppRouter = typeof appRouter;
tsimport { initTRPC } from '@trpc/server';export const t = initTRPC.create();const publicProcedure = t.procedure;export const appRouter = t.router({hello: publicProcedure.input((value): string => {if (typeof value === 'string') {return value;}throw new Error('Input is not a string');}).output((value): string => {if (typeof value === 'string') {return value;}throw new Error('Output is not a string');}).query((opts) => {const { input } = opts;// ^?return `hello ${input}`;}),});export type AppRouter = typeof appRouter;
Biblioteksintegrationer
tRPC fungerar färdigt ur lådan med ett antal populära validerings- och parsningsbibliotek. Nedan följer några exempel på användning med validerare som vi officiellt underhåller stöd för.
Med Zod
Zod är vårt standardrekommendation. Det har ett starkt ekosystem som gör det till ett utmärkt val att använda i flera delar av din kodbas. Om du inte har någon egen åsikt och vill ha ett kraftfullt bibliotek som inte begränsar framtida behov är Zod ett utmärkt val.
tsimport { initTRPC } from '@trpc/server';import { z } from 'zod';export const t = initTRPC.create();const publicProcedure = t.procedure;export const appRouter = t.router({hello: publicProcedure.input(z.object({name: z.string(),}),).output(z.object({greeting: z.string(),}),).query(({ input }) => {// ^?return {greeting: `hello ${input.name}`,};}),});export type AppRouter = typeof appRouter;
tsimport { initTRPC } from '@trpc/server';import { z } from 'zod';export const t = initTRPC.create();const publicProcedure = t.procedure;export const appRouter = t.router({hello: publicProcedure.input(z.object({name: z.string(),}),).output(z.object({greeting: z.string(),}),).query(({ input }) => {// ^?return {greeting: `hello ${input.name}`,};}),});export type AppRouter = typeof appRouter;
Med Yup
tsimport { initTRPC } from '@trpc/server';import * as yup from 'yup';export const t = initTRPC.create();const publicProcedure = t.procedure;export const appRouter = t.router({hello: publicProcedure.input(yup.object({name: yup.string().required(),}),).output(yup.object({greeting: yup.string().required(),}),).query(({ input }) => {// ^?return {greeting: `hello ${input.name}`,};}),});export type AppRouter = typeof appRouter;
tsimport { initTRPC } from '@trpc/server';import * as yup from 'yup';export const t = initTRPC.create();const publicProcedure = t.procedure;export const appRouter = t.router({hello: publicProcedure.input(yup.object({name: yup.string().required(),}),).output(yup.object({greeting: yup.string().required(),}),).query(({ input }) => {// ^?return {greeting: `hello ${input.name}`,};}),});export type AppRouter = typeof appRouter;
Med Superstruct
tsimport { initTRPC } from '@trpc/server';import { object, string } from 'superstruct';export const t = initTRPC.create();const publicProcedure = t.procedure;export const appRouter = t.router({hello: publicProcedure.input(object({ name: string() })).output(object({ greeting: string() })).query(({ input }) => {// ^?return {greeting: `hello ${input.name}`,};}),});export type AppRouter = typeof appRouter;
tsimport { initTRPC } from '@trpc/server';import { object, string } from 'superstruct';export const t = initTRPC.create();const publicProcedure = t.procedure;export const appRouter = t.router({hello: publicProcedure.input(object({ name: string() })).output(object({ greeting: string() })).query(({ input }) => {// ^?return {greeting: `hello ${input.name}`,};}),});export type AppRouter = typeof appRouter;
Med scale-ts
tsimport { initTRPC } from '@trpc/server';import * as $ from 'scale-codec';export const t = initTRPC.create();const publicProcedure = t.procedure;export const appRouter = t.router({hello: publicProcedure.input($.object($.field('name', $.str))).output($.object($.field('greeting', $.str))).query(({ input }) => {// ^?return {greeting: `hello ${input.name}`,};}),});export type AppRouter = typeof appRouter;
tsimport { initTRPC } from '@trpc/server';import * as $ from 'scale-codec';export const t = initTRPC.create();const publicProcedure = t.procedure;export const appRouter = t.router({hello: publicProcedure.input($.object($.field('name', $.str))).output($.object($.field('greeting', $.str))).query(({ input }) => {// ^?return {greeting: `hello ${input.name}`,};}),});export type AppRouter = typeof appRouter;
Med Typia
tsimport { initTRPC } from '@trpc/server';import typia from 'typia';import { v4 } from 'uuid';import { IBbsArticle } from '../structures/IBbsArticle';const t = initTRPC.create();const publicProcedure = t.procedure;export const appRouter = t.router({store: publicProcedure.input(typia.createAssert<IBbsArticle.IStore>()).output(typia.createAssert<IBbsArticle>()).query(({ input }) => {return {id: v4(),writer: input.writer,title: input.title,body: input.body,created_at: new Date().toString(),};}),});export type AppRouter = typeof appRouter;
tsimport { initTRPC } from '@trpc/server';import typia from 'typia';import { v4 } from 'uuid';import { IBbsArticle } from '../structures/IBbsArticle';const t = initTRPC.create();const publicProcedure = t.procedure;export const appRouter = t.router({store: publicProcedure.input(typia.createAssert<IBbsArticle.IStore>()).output(typia.createAssert<IBbsArticle>()).query(({ input }) => {return {id: v4(),writer: input.writer,title: input.title,body: input.body,created_at: new Date().toString(),};}),});export type AppRouter = typeof appRouter;
Med ArkType
tsimport { initTRPC } from '@trpc/server';import { type } from 'arktype';export const t = initTRPC.create();const publicProcedure = t.procedure;export const appRouter = t.router({hello: publicProcedure.input(type({ name: 'string' }).assert).output(type({ greeting: 'string' }).assert).query(({ input }) => {// ^?return {greeting: `hello ${input.name}`,};}),});export type AppRouter = typeof appRouter;
tsimport { initTRPC } from '@trpc/server';import { type } from 'arktype';export const t = initTRPC.create();const publicProcedure = t.procedure;export const appRouter = t.router({hello: publicProcedure.input(type({ name: 'string' }).assert).output(type({ greeting: 'string' }).assert).query(({ input }) => {// ^?return {greeting: `hello ${input.name}`,};}),});export type AppRouter = typeof appRouter;
Med @effect/schema
tsimport * as Schema from '@effect/schema/Schema';import { initTRPC } from '@trpc/server';export const t = initTRPC.create();const publicProcedure = t.procedure;export const appRouter = t.router({hello: publicProcedure.input(Schema.decodeUnknownSync(Schema.Struct({ name: Schema.String }))).output(Schema.decodeUnknownSync(Schema.Struct({ greeting: Schema.String })),).query(({ input }) => {// ^?return {greeting: `hello ${input.name}`,};}),});export type AppRouter = typeof appRouter;
tsimport * as Schema from '@effect/schema/Schema';import { initTRPC } from '@trpc/server';export const t = initTRPC.create();const publicProcedure = t.procedure;export const appRouter = t.router({hello: publicProcedure.input(Schema.decodeUnknownSync(Schema.Struct({ name: Schema.String }))).output(Schema.decodeUnknownSync(Schema.Struct({ greeting: Schema.String })),).query(({ input }) => {// ^?return {greeting: `hello ${input.name}`,};}),});export type AppRouter = typeof appRouter;
Med runtypes
tsimport { initTRPC } from '@trpc/server';import * as T from 'runtypes';const t = initTRPC.create();const publicProcedure = t.procedure;export const appRouter = t.router({hello: publicProcedure.input(T.Record({ name: T.String })).output(T.Record({ greeting: T.String })).query(({ input }) => {// ^?return {greeting: `hello ${input.name}`,};}),});export type AppRouter = typeof appRouter;
tsimport { initTRPC } from '@trpc/server';import * as T from 'runtypes';const t = initTRPC.create();const publicProcedure = t.procedure;export const appRouter = t.router({hello: publicProcedure.input(T.Record({ name: T.String })).output(T.Record({ greeting: T.String })).query(({ input }) => {// ^?return {greeting: `hello ${input.name}`,};}),});export type AppRouter = typeof appRouter;
Med Valibot
tsimport { wrap } from '@decs/typeschema';import { initTRPC } from '@trpc/server';import { object, string } from 'valibot';export const t = initTRPC.create();const publicProcedure = t.procedure;export const appRouter = t.router({hello: publicProcedure.input(wrap(object({ name: string() }))).output(wrap(object({ greeting: string() }))).query(({ input }) => {// ^?return {greeting: `hello ${input.name}`,};}),});export type AppRouter = typeof appRouter;
tsimport { wrap } from '@decs/typeschema';import { initTRPC } from '@trpc/server';import { object, string } from 'valibot';export const t = initTRPC.create();const publicProcedure = t.procedure;export const appRouter = t.router({hello: publicProcedure.input(wrap(object({ name: string() }))).output(wrap(object({ greeting: string() }))).query(({ input }) => {// ^?return {greeting: `hello ${input.name}`,};}),});export type AppRouter = typeof appRouter;
Bidra med din egen valideringsbibliotek
Om du arbetar med ett valideringsbibliotek som stöder tRPC-användning, är du välkommen att öppna en PR för denna sida med motsvarande användning som i de andra exemplen här, samt en länk till din dokumentation.
Integration med tRPC är i de flesta fall så enkel som att uppfylla ett av flera befintliga typgränssnitt, men i vissa fall kan vi acceptera en PR för att lägga till ett nytt stött gränssnitt. Du är välkommen att öppna ett ärende för diskussion. Du kan kolla de befintliga stödda gränssnitten här: