Hoppa till huvudinnehållet
Version: 10.x

Snabbstart

Inofficiell Beta-översättning

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 delar av din kodbas. I denna snabbstart håller vi det enkelt och använder endast vanilla client. För ramverksspecifika guider, kolla in användning med React och användning med Next.js.

Krav
  • tRPC kräver TypeScript >= 4.7.0
  • Vi rekommenderar starkt att du använder "strict": true i din tsconfig.json eftersom vi inte officiellt stöder icke-strikt läge.

Börja med att installera paketen @trpc/server och @trpc/client:

sh
npm install @trpc/server @trpc/client
sh
npm install @trpc/server @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:

ts
type User = { id: string; name: string; };
userList: () => User[];
userById: (id: string) => User;
userCreate: (data: { name: string }) => User;
ts
type 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.ts
ts
import { initTRPC } from '@trpc/server';
 
/**
* Initialization of tRPC backend
* Should be done only once per backend!
*/
const t = initTRPC.create();
 
/**
* Export reusable router and procedure helpers
* that can be used throughout the router
*/
export const router = t.router;
export const publicProcedure = t.procedure;
server/trpc.ts
ts
import { initTRPC } from '@trpc/server';
 
/**
* Initialization of tRPC backend
* Should be done only once per backend!
*/
const t = initTRPC.create();
 
/**
* Export reusable router and procedure helpers
* that can be used throughout the router
*/
export const router = t.router;
export const publicProcedure = 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.ts
ts
import { router } from './trpc';
 
const appRouter = router({
// ...
});
 
// Export type router type signature,
// NOT the router itself.
export type AppRouter = typeof appRouter;
server/index.ts
ts
import { router } from './trpc';
 
const appRouter = router({
// ...
});
 
// Export type router type signature,
// NOT the router itself.
export type AppRouter = typeof appRouter;

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.ts
ts
import { db } from './db';
import { publicProcedure, router } from './trpc';
 
const appRouter = router({
userList: publicProcedure.query(async () => {
// Retrieve users from a datasource, this is an imaginary database
const users = await db.user.findMany();
const users: User[]
return users;
}),
});
server/index.ts
ts
import { db } from './db';
import { publicProcedure, router } from './trpc';
 
const appRouter = router({
userList: publicProcedure.query(async () => {
// Retrieve users from a datasource, this is an imaginary database
const users = await db.user.findMany();
const users: User[]
return users;
}),
});

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:

The input parser can be any ZodType, e.g. z.string() or z.object().



server.ts
ts
import { z } from 'zod';
import { db } from './db';
import { publicProcedure, router } from './trpc';
 
const appRouter = router({
// ...
userById: publicProcedure.input(z.string()).query(async (opts) => {
const { input } = opts;
const input: string
// Retrieve the user with the given ID
const user = await db.user.findById(input);
const user: User | undefined
return user;
}),
});
server.ts
ts
import { z } from 'zod';
import { db } from './db';
import { publicProcedure, router } from './trpc';
 
const appRouter = router({
// ...
userById: publicProcedure.input(z.string()).query(async (opts) => {
const { input } = opts;
const input: string
// Retrieve the user with the given ID
const user = await db.user.findById(input);
const user: User | undefined
return user;
}),
});
info

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.ts
ts
const appRouter = router({
// ...
userCreate: publicProcedure
.input(z.object({ name: z.string() }))
.mutation(async (opts) => {
const { input } = opts;
const input: { name: string; }
// Create a new user in the database
const user = await db.user.create(input);
const user: { name: string; id: string; }
return user;
}),
});
server.ts
ts
const appRouter = router({
// ...
userCreate: publicProcedure
.input(z.object({ name: z.string() }))
.mutation(async (opts) => {
const { input } = opts;
const input: { name: string; }
// Create a new user in the database
const user = await db.user.create(input);
const user: { name: string; id: string; }
return user;
}),
});

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.ts
ts
import { createHTTPServer } from '@trpc/server/adapters/standalone';
import { router } from './trpc';
 
const appRouter = router({
// ...
});
 
const server = createHTTPServer({
router: appRouter,
});
 
server.listen(3000);
server/index.ts
ts
import { createHTTPServer } from '@trpc/server/adapters/standalone';
import { router } from './trpc';
 
const appRouter = router({
// ...
});
 
const server = createHTTPServer({
router: appRouter,
});
 
server.listen(3000);
See the full backend code
server/db.ts
ts
type User = { id: string; name: string };
 
// Imaginary database
const users: User[] = [];
export const db = {
user: {
findMany: async () => users,
findById: async (id: string) => users.find((user) => user.id === id),
create: async (data: { name: string }) => {
const user = { id: String(users.length + 1), ...data };
users.push(user);
return user;
},
},
};
server/db.ts
ts
type User = { id: string; name: string };
 
// Imaginary database
const users: User[] = [];
export const db = {
user: {
findMany: async () => users,
findById: async (id: string) => users.find((user) => user.id === id),
create: async (data: { name: string }) => {
const user = { id: String(users.length + 1), ...data };
users.push(user);
return user;
},
},
};

server/trpc.ts
ts
import { initTRPC } from '@trpc/server';
 
const t = initTRPC.create();
 
export const router = t.router;
export const publicProcedure = t.procedure;
server/trpc.ts
ts
import { initTRPC } from '@trpc/server';
 
const t = initTRPC.create();
 
export const router = t.router;
export const publicProcedure = t.procedure;

server/index.ts
ts
import { createHTTPServer } from "@trpc/server/adapters/standalone";
import { z } from "zod";
import { db } from "./db";
import { publicProcedure, router } from "./trpc";
 
const appRouter = router({
userList: publicProcedure
.query(async () => {
const users = await db.user.findMany();
return users;
}),
userById: publicProcedure
.input(z.string())
.query(async (opts) => {
const { input } = opts;
const user = await db.user.findById(input);
return user;
}),
userCreate: publicProcedure
.input(z.object({ name: z.string() }))
.mutation(async (opts) => {
const { input } = opts;
const user = await db.user.create(input);
return user;
}),
});
 
export type AppRouter = typeof appRouter;
 
const server = createHTTPServer({
router: appRouter,
});
 
server.listen(3000);
server/index.ts
ts
import { createHTTPServer } from "@trpc/server/adapters/standalone";
import { z } from "zod";
import { db } from "./db";
import { publicProcedure, router } from "./trpc";
 
const appRouter = router({
userList: publicProcedure
.query(async () => {
const users = await db.user.findMany();
return users;
}),
userById: publicProcedure
.input(z.string())
.query(async (opts) => {
const { input } = opts;
const user = await db.user.findById(input);
return user;
}),
userCreate: publicProcedure
.input(z.object({ name: z.string() }))
.mutation(async (opts) => {
const { input } = opts;
const user = await db.user.create(input);
return user;
}),
});
 
export type AppRouter = typeof appRouter;
 
const server = 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.ts
ts
import { createTRPCProxyClient, 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.
const trpc = createTRPCProxyClient<AppRouter>({
links: [
httpBatchLink({
url: 'http://localhost:3000',
}),
],
});
client/index.ts
ts
import { createTRPCProxyClient, 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.
const trpc = createTRPCProxyClient<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.ts
ts
// Inferred types
const user = await trpc.userById.query('1');
const user: { name: string; id: string; } | undefined
 
const createdUser = await trpc.userCreate.mutate({ name: 'sachinraja' });
const createdUser: { name: string; id: string; }
client/index.ts
ts
// Inferred types
const user = await trpc.userById.query('1');
const user: { name: string; id: string; } | undefined
 
const createdUser = await trpc.userCreate.mutate({ name: 'sachinraja' });
const createdUser: { name: string; id: string; }

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.ts
ts
// Full autocompletion on your routes
trpc.u;
      
client/index.ts
ts
// Full autocompletion on your routes
trpc.u;
      

Prova det själv!

Nästa steg

tips

Vi uppmuntrar dig starkt att kolla in exempelapparna för att lära dig hur tRPC installeras i ditt favoritramverk.

tips

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.