Snabbstart
Denna sida har översatts av PageTurner AI (beta). Inte officiellt godkänd av projektet. Hittade du ett fel? Rapportera problem →
tRPC kombinerar koncept från REST och GraphQL. Om du inte är bekant med något av dem, ta en titt på de viktigaste koncepten.
Installation
tRPC är uppdelat i flera paket så du kan installera endast det du behöver. Se till att installera paketen i rätt sektioner av din kodbas. I denna snabbstart håller vi det enkelt och använder endast vanilla-klienten. För framework-guider, kolla in användning med React och användning med Next.js.
- tRPC kräver TypeScript >=5.7.2
- Vi rekommenderar starkt att du använder
"strict": truei dintsconfig.jsoneftersom vi inte officiellt stöder icke-strikt läge.
Börja med att installera paketen @trpc/server och @trpc/client:
- npm
- yarn
- pnpm
- bun
- deno
npm install @trpc/server @trpc/client
yarn add @trpc/server @trpc/client
pnpm add @trpc/server @trpc/client
bun add @trpc/server @trpc/client
deno add npm:@trpc/server npm:@trpc/client
Definiera en backend-router
Låt oss gå igenom stegen för att bygga ett typesäkert API med tRPC. Till att börja med kommer detta API innehålla tre endpoints med följande TypeScript-signaturer:
tstype User = { id: string; name: string; };userList: () => User[];userById: (id: string) => User;userCreate: (data: { name: string }) => User;
tstype User = { id: string; name: string; };userList: () => User[];userById: (id: string) => User;userCreate: (data: { name: string }) => User;
1. Skapa en router-instans
Först initialiserar vi tRPC-backenden. Det är god praxis att göra detta i en separat fil och exportera återanvändbara hjälpfunktioner istället för hela tRPC-objektet.
server/trpc.tstsimport {initTRPC } from '@trpc/server';/*** Initialization of tRPC backend* Should be done only once per backend!*/constt =initTRPC .create ();/*** Export reusable router and procedure helpers* that can be used throughout the router*/export constrouter =t .router ;export constpublicProcedure =t .procedure ;
server/trpc.tstsimport {initTRPC } from '@trpc/server';/*** Initialization of tRPC backend* Should be done only once per backend!*/constt =initTRPC .create ();/*** Export reusable router and procedure helpers* that can be used throughout the router*/export constrouter =t .router ;export constpublicProcedure =t .procedure ;
Därefter initialiserar vi vår huvudrouter-instans, ofta kallad appRouter, där vi senare lägger till procedurer. Slutligen behöver vi exportera routertypen som vi senare använder på klientsidan.
server/index.tstsimport {router } from './trpc';constappRouter =router ({// ...});// Export type router type signature,// NOT the router itself.export typeAppRouter = typeofappRouter ;
server/index.tstsimport {router } from './trpc';constappRouter =router ({// ...});// Export type router type signature,// NOT the router itself.export typeAppRouter = typeofappRouter ;
2. Lägg till en query-procedure
Använd publicProcedure.query() för att lägga till en query-procedure till routern.
Följande skapar en query-procedure kallad userList som returnerar en användarlista från vår databas:
server/index.tstsimport {db } from './db';import {publicProcedure ,router } from './trpc';constappRouter =router ({userList :publicProcedure .query (async () => {// Retrieve users from a datasource, this is an imaginary databaseconstusers = awaitdb .user .findMany ();returnusers ;}),});
server/index.tstsimport {db } from './db';import {publicProcedure ,router } from './trpc';constappRouter =router ({userList :publicProcedure .query (async () => {// Retrieve users from a datasource, this is an imaginary databaseconstusers = awaitdb .user .findMany ();returnusers ;}),});
3. Använda input-parser för att validera procedure-input
För att implementera userById-proceduren behöver vi acceptera input från klienten. tRPC låter dig definiera input-parsers för att validera och tolka inputen. Du kan definiera din egen input-parser eller använda ett valfri valideringsbibliotek som zod, yup eller superstruct.
Du definierar din input-parser på publicProcedure.input(), som sedan kan nås i resolver-funktionen som visas nedan:
- Vanilla
- Zod
- Yup
- Valibot
The input parser should be a function that validates and casts the input of this procedure. It should return a strongly typed value when the input is valid or throw an error if the input is invalid.
server/index.tstsconstappRouter =router ({// ...userById :publicProcedure // The input is unknown at this time. A client could have sent// us anything so we won't assume a certain data type..input ((val : unknown) => {// If the value is of type string, return it.// It will now be inferred as a string.if (typeofval === 'string') returnval ;// Uh oh, looks like that input wasn't a string.// We will throw an error instead of running the procedure.throw newError (`Invalid input: ${typeofval }`);}).query (async (opts ) => {const {input } =opts ;// Retrieve the user with the given IDconstuser = awaitdb .user .findById (input );returnuser ;}),});
server/index.tstsconstappRouter =router ({// ...userById :publicProcedure // The input is unknown at this time. A client could have sent// us anything so we won't assume a certain data type..input ((val : unknown) => {// If the value is of type string, return it.// It will now be inferred as a string.if (typeofval === 'string') returnval ;// Uh oh, looks like that input wasn't a string.// We will throw an error instead of running the procedure.throw newError (`Invalid input: ${typeofval }`);}).query (async (opts ) => {const {input } =opts ;// Retrieve the user with the given IDconstuser = awaitdb .user .findById (input );returnuser ;}),});
The input parser can be any ZodType, e.g. z.string() or z.object().
server.tstsimport {z } from 'zod';constappRouter =router ({// ...userById :publicProcedure .input (z .string ()).query (async (opts ) => {const {input } =opts ;// Retrieve the user with the given IDconstuser = awaitdb .user .findById (input );returnuser ;}),});
server.tstsimport {z } from 'zod';constappRouter =router ({// ...userById :publicProcedure .input (z .string ()).query (async (opts ) => {const {input } =opts ;// Retrieve the user with the given IDconstuser = awaitdb .user .findById (input );returnuser ;}),});
The input parser can be any YupSchema, e.g. yup.string() or yup.object().
server.tstsimport * asyup from 'yup';constappRouter =router ({// ...userById :publicProcedure .input (yup .string ().required ()).query (async (opts ) => {const {input } =opts ;// Retrieve the user with the given IDconstuser = awaitdb .user .findById (input );returnuser ;}),});
server.tstsimport * asyup from 'yup';constappRouter =router ({// ...userById :publicProcedure .input (yup .string ().required ()).query (async (opts ) => {const {input } =opts ;// Retrieve the user with the given IDconstuser = awaitdb .user .findById (input );returnuser ;}),});
The input parser can be any Valibot schema, e.g. v.string() or v.object().
server.tstsimport * asv from 'valibot';constappRouter =router ({// ...userById :publicProcedure .input (v .string ()).query (async (opts ) => {const {input } =opts ;// Retrieve the user with the given IDconstuser = awaitdb .user .findById (input );returnuser ;}),});
server.tstsimport * asv from 'valibot';constappRouter =router ({// ...userById :publicProcedure .input (v .string ()).query (async (opts ) => {const {input } =opts ;// Retrieve the user with the given IDconstuser = awaitdb .user .findById (input );returnuser ;}),});
I resten av denna dokumentation kommer vi att använda zod som vårt valideringsbibliotek.
4. Lägga till en mutation-procedure
Liknande GraphQL gör tRPC en åtskillnad mellan query- och mutation-procedurer.
Sättet en procedure fungerar på servern skiljer sig inte mycket mellan queries och mutations. Metodnamnet är annorlunda, och hur klienten använder proceduren ändras - men allt annat är detsamma!
Låt oss lägga till en userCreate-mutation genom att lägga till den som en ny egenskap på vårt router-objekt:
server.tstsconstappRouter =router ({// ...userCreate :publicProcedure .input (z .object ({name :z .string () })).mutation (async (opts ) => {const {input } =opts ;// Create a new user in the databaseconstuser = awaitdb .user .create (input );returnuser ;}),});
server.tstsconstappRouter =router ({// ...userCreate :publicProcedure .input (z .object ({name :z .string () })).mutation (async (opts ) => {const {input } =opts ;// Create a new user in the databaseconstuser = awaitdb .user .create (input );returnuser ;}),});
Serva API:et
Nu när vi har definierat vår router kan vi serva den. tRPC har många adapters så du kan använda vilket backend-ramverk du vill. För att hålla det enkelt använder vi standalone-adaptern.
server/index.tstsimport {createHTTPServer } from '@trpc/server/adapters/standalone';constappRouter =router ({// ...});constserver =createHTTPServer ({router :appRouter ,});server .listen (3000);
server/index.tstsimport {createHTTPServer } from '@trpc/server/adapters/standalone';constappRouter =router ({// ...});constserver =createHTTPServer ({router :appRouter ,});server .listen (3000);
See the full backend code
server/db.tststypeUser = {id : string;name : string };// Imaginary databaseconstusers :User [] = [];export constdb = {user : {findMany : async () =>users ,findById : async (id : string) =>users .find ((user ) =>user .id ===id ),create : async (data : {name : string }) => {constuser = {id :String (users .length + 1), ...data };users .push (user );returnuser ;},},};
server/db.tststypeUser = {id : string;name : string };// Imaginary databaseconstusers :User [] = [];export constdb = {user : {findMany : async () =>users ,findById : async (id : string) =>users .find ((user ) =>user .id ===id ),create : async (data : {name : string }) => {constuser = {id :String (users .length + 1), ...data };users .push (user );returnuser ;},},};
server/trpc.tstsimport {initTRPC } from '@trpc/server';constt =initTRPC .create ();export constrouter =t .router ;export constpublicProcedure =t .procedure ;
server/trpc.tstsimport {initTRPC } from '@trpc/server';constt =initTRPC .create ();export constrouter =t .router ;export constpublicProcedure =t .procedure ;
server/index.tstsimport {createHTTPServer } from "@trpc/server/adapters/standalone";import {z } from "zod";import {db } from "./db";import {publicProcedure ,router } from "./trpc";constappRouter =router ({userList :publicProcedure .query (async () => {constusers = awaitdb .user .findMany ();returnusers ;}),userById :publicProcedure .input (z .string ()).query (async (opts ) => {const {input } =opts ;constuser = awaitdb .user .findById (input );returnuser ;}),userCreate :publicProcedure .input (z .object ({name :z .string () })).mutation (async (opts ) => {const {input } =opts ;constuser = awaitdb .user .create (input );returnuser ;}),});export typeAppRouter = typeofappRouter ;constserver =createHTTPServer ({router :appRouter ,});server .listen (3000);
server/index.tstsimport {createHTTPServer } from "@trpc/server/adapters/standalone";import {z } from "zod";import {db } from "./db";import {publicProcedure ,router } from "./trpc";constappRouter =router ({userList :publicProcedure .query (async () => {constusers = awaitdb .user .findMany ();returnusers ;}),userById :publicProcedure .input (z .string ()).query (async (opts ) => {const {input } =opts ;constuser = awaitdb .user .findById (input );returnuser ;}),userCreate :publicProcedure .input (z .object ({name :z .string () })).mutation (async (opts ) => {const {input } =opts ;constuser = awaitdb .user .create (input );returnuser ;}),});export typeAppRouter = typeofappRouter ;constserver =createHTTPServer ({router :appRouter ,});server .listen (3000);
Använda din nya backend på klienten
Låt oss nu gå vidare till klientsidan och ta tillvara kraften i end-to-end typesafety. När vi importerar AppRouter-typen för klienten att använda har vi uppnått fullständig typesafety i vårt system utan att läcka några implementeringsdetaljer till klienten.
1. Konfigurera tRPC-klienten
client/index.tstsimport {createTRPCClient ,httpBatchLink } from '@trpc/client';import type {AppRouter } from './server';// 👆 **type-only** import// Pass AppRouter as generic here. 👇 This lets the `trpc` object know// what procedures are available on the server and their input/output types.consttrpc =createTRPCClient <AppRouter >({links : [httpBatchLink ({url : 'http://localhost:3000',}),],});
client/index.tstsimport {createTRPCClient ,httpBatchLink } from '@trpc/client';import type {AppRouter } from './server';// 👆 **type-only** import// Pass AppRouter as generic here. 👇 This lets the `trpc` object know// what procedures are available on the server and their input/output types.consttrpc =createTRPCClient <AppRouter >({links : [httpBatchLink ({url : 'http://localhost:3000',}),],});
Länkar i tRPC fungerar liknande som länkar i GraphQL - de låter oss kontrollera dataflödet innan det skickas till servern. I exemplet ovan använder vi httpBatchLink, som automatiskt samlar ihop flera anrop till en enda HTTP-förfrågan. För mer djupgående information om länkar, se länkdokumentationen.
2. Frågor & mutationer
Du har nu tillgång till dina API-procedurer via trpc-objektet. Prova det!
client/index.tsts// Inferred typesconstuser = awaittrpc .userById .query ('1');constcreatedUser = awaittrpc .userCreate .mutate ({name : 'sachinraja' });
client/index.tsts// Inferred typesconstuser = awaittrpc .userById .query ('1');constcreatedUser = awaittrpc .userCreate .mutate ({name : 'sachinraja' });
Fullständig autocompletion
Du kan öppna din Intellisense för att utforska ditt API direkt i frontend-koden. Där hittar du alla dina procedurvägar väntande på dig, tillsammans med metoderna för att anropa dem.
client/index.tsts// Full autocompletion on your routestrpc .u ;
client/index.tsts// Full autocompletion on your routestrpc .u ;
Prova det själv!
Nästa steg
Vi uppmuntrar dig starkt att kolla in exempelapparna för att lära dig hur tRPC installeras i ditt favoritramverk.
Som standard kommer tRPC att mappa komplexa typer som Date till deras JSON-ekvivalent (string i fallet med Date). Om du vill behålla integriteten hos dessa typer är det enklaste sättet att använda superjson som en Data Transformer.
tRPC inkluderar mer avancerade klientverktyg speciellt designade för React-projekt och Next.js.
-
Användning med React (klientsidan)
- React-integrering (Rekommenderad) ->
@trpc/tanstack-react-query - React-integrering (Klassisk) ->
@trpc/react-query - Om du är osäker, använd
Recommended
- React-integrering (Rekommenderad) ->