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. Validerare används också för att härleda typerna för indata och utdata (med hjälp av Standard Schema-gränssnittet om tillgängligt, eller anpassade gränssnitt för validerare som stöds). Vi har förstahandsstöd för många populära validerare, och du kan integrera validerare som vi inte direkt stöder.
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// Our examples use Zod by default, but usage with other libraries is identicalimport {z } from 'zod';export constt =initTRPC .create ();constpublicProcedure =t .procedure ;export constappRouter =t .router ({hello :publicProcedure .input (z .object ({name :z .string (),}),).query ((opts ) => {constname =opts .input .name ;return {greeting : `Hello ${opts .input .name }`,};}),});
ts// Our examples use Zod by default, but usage with other libraries is identicalimport {z } from 'zod';export constt =initTRPC .create ();constpublicProcedure =t .procedure ;export constappRouter =t .router ({hello :publicProcedure .input (z .object ({name :z .string (),}),).query ((opts ) => {constname =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.
tsconstbaseProcedure =t .procedure .input (z .object ({townName :z .string () })).use ((opts ) => {constinput =opts .input ;console .log (`Handling request with user from: ${input .townName }`);returnopts .next ();});export constappRouter =t .router ({hello :baseProcedure .input (z .object ({name :z .string (),}),).query ((opts ) => {constinput =opts .input ;return {greeting : `Hello ${input .name }, my friend from ${input .townName }`,};}),});
tsconstbaseProcedure =t .procedure .input (z .object ({townName :z .string () })).use ((opts ) => {constinput =opts .input ;console .log (`Handling request with user from: ${input .townName }`);returnopts .next ();});export constappRouter =t .router ({hello :baseProcedure .input (z .object ({name :z .string (),}),).query ((opts ) => {constinput =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.
tsimport {z } from 'zod';export constt =initTRPC .create ();constpublicProcedure =t .procedure ;export constappRouter =t .router ({hello :publicProcedure .output (z .object ({greeting :z .string (),}),).query ((opts ) => {return {gre ,};}),});
tsimport {z } from 'zod';export constt =initTRPC .create ();constpublicProcedure =t .procedure ;export constappRouter =t .router ({hello :publicProcedure .output (z .object ({greeting :z .string (),}),).query ((opts ) => {return {gre ,};}),});
Validering av utdata för prenumerationer
Eftersom prenumerationer är asynkra iteratorer kan du använda samma valideringstekniker som ovan.
Läs mer i prenumerationsguiden.
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 constt =initTRPC .create ();constpublicProcedure =t .procedure ;export constappRouter =t .router ({hello :publicProcedure .input ((value ): string => {if (typeofvalue === 'string') {returnvalue ;}throw newError ('Input is not a string');}).output ((value ): string => {if (typeofvalue === 'string') {returnvalue ;}throw newError ('Output is not a string');}).query ((opts ) => {const {input } =opts ;return `hello ${input }`;}),});export typeAppRouter = typeofappRouter ;
tsimport {initTRPC } from '@trpc/server';export constt =initTRPC .create ();constpublicProcedure =t .procedure ;export constappRouter =t .router ({hello :publicProcedure .input ((value ): string => {if (typeofvalue === 'string') {returnvalue ;}throw newError ('Input is not a string');}).output ((value ): string => {if (typeofvalue === 'string') {returnvalue ;}throw newError ('Output is not a string');}).query ((opts ) => {const {input } =opts ;return `hello ${input }`;}),});export typeAppRouter = typeofappRouter ;
Biblioteksintegrationer
tRPC fungerar färdigt med ett antal populära validerings- och parsningsbibliotek, inklusive alla bibliotek som följer Standard Schema. Nedan följer några exempel på användning med validerare som vi officiellt stöder.
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 constt =initTRPC .create ();constpublicProcedure =t .procedure ;export constappRouter =t .router ({hello :publicProcedure .input (z .object ({name :z .string (),}),).output (z .object ({greeting :z .string (),}),).query (({input }) => {return {greeting : `hello ${input .name }`,};}),});export typeAppRouter = typeofappRouter ;
tsimport {initTRPC } from '@trpc/server';import {z } from 'zod';export constt =initTRPC .create ();constpublicProcedure =t .procedure ;export constappRouter =t .router ({hello :publicProcedure .input (z .object ({name :z .string (),}),).output (z .object ({greeting :z .string (),}),).query (({input }) => {return {greeting : `hello ${input .name }`,};}),});export typeAppRouter = typeofappRouter ;
Med Yup
tsimport {initTRPC } from '@trpc/server';import * asyup from 'yup';export constt =initTRPC .create ();constpublicProcedure =t .procedure ;export constappRouter =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 typeAppRouter = typeofappRouter ;
tsimport {initTRPC } from '@trpc/server';import * asyup from 'yup';export constt =initTRPC .create ();constpublicProcedure =t .procedure ;export constappRouter =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 typeAppRouter = typeofappRouter ;
Med Superstruct
tsimport {initTRPC } from '@trpc/server';import {object ,string } from 'superstruct';export constt =initTRPC .create ();constpublicProcedure =t .procedure ;export constappRouter =t .router ({hello :publicProcedure .input (object ({name :string () })).output (object ({greeting :string () })).query (({input }) => {return {greeting : `hello ${input .name }`,};}),});export typeAppRouter = typeofappRouter ;
tsimport {initTRPC } from '@trpc/server';import {object ,string } from 'superstruct';export constt =initTRPC .create ();constpublicProcedure =t .procedure ;export constappRouter =t .router ({hello :publicProcedure .input (object ({name :string () })).output (object ({greeting :string () })).query (({input }) => {return {greeting : `hello ${input .name }`,};}),});export typeAppRouter = typeofappRouter ;
Med scale-ts
tsimport {initTRPC } from '@trpc/server';import * as$ from 'scale-codec';export constt =initTRPC .create ();constpublicProcedure =t .procedure ;export constappRouter =t .router ({hello :publicProcedure .input ($ .object ($ .field ('name',$ .str ))).output ($ .object ($ .field ('greeting',$ .str ))).query (({input }) => {return {greeting : `hello ${input .name }`,};}),});export typeAppRouter = typeofappRouter ;
tsimport {initTRPC } from '@trpc/server';import * as$ from 'scale-codec';export constt =initTRPC .create ();constpublicProcedure =t .procedure ;export constappRouter =t .router ({hello :publicProcedure .input ($ .object ($ .field ('name',$ .str ))).output ($ .object ($ .field ('greeting',$ .str ))).query (({input }) => {return {greeting : `hello ${input .name }`,};}),});export typeAppRouter = typeofappRouter ;
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' })).query((opts) => {return {greeting: `hello ${opts.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' })).query((opts) => {return {greeting: `hello ${opts.input.name}`,};}),});export type AppRouter = typeof appRouter;
Med effect
tsimport { initTRPC } from '@trpc/server';import { Schema } from 'effect';export const t = initTRPC.create();const publicProcedure = t.procedure;export const appRouter = t.router({hello: publicProcedure.input(Schema.standardSchemaV1(Schema.Struct({ name: Schema.String }))).output(Schema.standardSchemaV1(Schema.Struct({ greeting: Schema.String }))).query(({ input }) => {// ^?return {greeting: `hello ${input.name}`,};}),});export type AppRouter = typeof appRouter;
tsimport { initTRPC } from '@trpc/server';import { Schema } from 'effect';export const t = initTRPC.create();const publicProcedure = t.procedure;export const appRouter = t.router({hello: publicProcedure.input(Schema.standardSchemaV1(Schema.Struct({ name: Schema.String }))).output(Schema.standardSchemaV1(Schema.Struct({ greeting: Schema.String }))).query(({ input }) => {// ^?return {greeting: `hello ${input.name}`,};}),});export type AppRouter = typeof appRouter;
Med Valibot
tsimport {initTRPC } from '@trpc/server';import * asv from 'valibot';export constt =initTRPC .create ();constpublicProcedure =t .procedure ;export constappRouter =t .router ({hello :publicProcedure .input (v .object ({name :v .string () })).output (v .object ({greeting :v .string () })).query (({input }) => {return {greeting : `hello ${input .name }`,};}),});export typeAppRouter = typeofappRouter ;
tsimport {initTRPC } from '@trpc/server';import * asv from 'valibot';export constt =initTRPC .create ();constpublicProcedure =t .procedure ;export constappRouter =t .router ({hello :publicProcedure .input (v .object ({name :v .string () })).output (v .object ({greeting :v .string () })).query (({input }) => {return {greeting : `hello ${input .name }`,};}),});export typeAppRouter = typeofappRouter ;
Med @robolex/sure
Du kan definiera egna feltyper och en funktion för att kasta fel om det behövs.
Som en bekvämlighet tillhandahåller @robolex/sure sure/src/err.ts:
ts// sure/src/err.tsexport const err = (schema) => (input) => {const [good, result] = schema(input);if (good) return result;throw result;};
ts// sure/src/err.tsexport const err = (schema) => (input) => {const [good, result] = schema(input);if (good) return result;throw result;};
tsimport { err, object, string } from '@robolex/sure';import { initTRPC } from '@trpc/server';export const t = initTRPC.create();const publicProcedure = t.procedure;export const appRouter = t.router({hello: publicProcedure.input(err(object({name: string,}),),).output(err(object({greeting: string,}),),).query(({ input }) => {// ^?return {greeting: `hello ${input.name}`,};}),});export type AppRouter = typeof appRouter;
tsimport { err, object, string } from '@robolex/sure';import { initTRPC } from '@trpc/server';export const t = initTRPC.create();const publicProcedure = t.procedure;export const appRouter = t.router({hello: publicProcedure.input(err(object({name: string,}),),).output(err(object({greeting: string,}),),).query(({ input }) => {// ^?return {greeting: `hello ${input.name}`,};}),});export type AppRouter = typeof appRouter;
Med TypeBox
tsimport { Type } from '@sinclair/typebox';import { initTRPC } from '@trpc/server';import { wrap } from '@typeschema/typebox';export const t = initTRPC.create();const publicProcedure = t.procedure;export const appRouter = t.router({hello: publicProcedure.input(wrap(Type.Object({ name: Type.String() }))).output(wrap(Type.Object({ greeting: Type.String() }))).query(({ input }) => {return {greeting: `hello ${input.name}`,};}),});export type AppRouter = typeof appRouter;
tsimport { Type } from '@sinclair/typebox';import { initTRPC } from '@trpc/server';import { wrap } from '@typeschema/typebox';export const t = initTRPC.create();const publicProcedure = t.procedure;export const appRouter = t.router({hello: publicProcedure.input(wrap(Type.Object({ name: Type.String() }))).output(wrap(Type.Object({ greeting: Type.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 lika enkelt som att uppfylla något av flera befintliga typergränssnitt. Att följa Standard Schema rekommenderas, men i vissa fall kan vi acceptera en PR för att lägga till ett nytt stött gränssnitt. Öppna gärna ett ärende för diskussion. Du kan se de befintliga stödda gränssnitten och funktionerna för parsning/validering i koden.