tRPC Core Concepts
What is tRPC?
tRPC (opens in a new tab) is a powerful library for building end-to-end typesafe APIs without the need for a code generator. It allows you to define your APIs using TypeScript, ensuring that your client and server are always in sync.
Why Choose tRPC?
- Type Safety: Ensures end-to-end type safety without the need for code generation.
- Productivity: Enhances developer productivity by reducing boilerplate code and runtime errors.
- Flexibility: Can be used with any framework, including React, Next.js, and even vanilla TypeScript projects.
- Lightweight: Minimal overhead compared to traditional REST or GraphQL.
Core Concepts
Routers and Procedures
tRPC revolves around the concept of routers and procedures. A router can contain multiple procedures, which are either queries or mutations.
- Router: A collection of related procedures.
- Procedure: A function exposed through the router, which can be a query (read-only operation) or a mutation (write operation).
Type Inference
tRPC leverages TypeScript's type inference to ensure that types are consistent across the client and server. When you define a router and its procedures, tRPC automatically infers the types for you.
Data Transformation
tRPC allows you to define custom data transformers for serializing and deserializing data, ensuring that your API can handle complex data structures seamlessly.
Middlewares
tRPC supports middlewares, allowing you to add custom logic to your procedures. This can include authentication, authorization, logging, etc.
Example Concepts
Defining a Router
Here's how you can define a simple router with a query and a mutation:
import { initTRPC } from '@trpc/server';
const t = initTRPC.create();
const appRouter = t.router({
getUser: t.procedure
.input(z.string())
.query(({ input }) => {
return { id: input, name: 'John Doe' };
}),
createUser: t.procedure
.input(z.object({ name: z.string() }))
.mutation(({ input }) => {
return { id: '1', ...input };
}),
});
export type AppRouter = typeof appRouter;
Type-Safe Client
With the router defined, tRPC ensures type safety on the client side:
import { createTRPCProxyClient, httpLink } from '@trpc/client';
import type { AppRouter } from './path/to/server';
const trpc = createTRPCProxyClient<AppRouter>({
links: [
httpLink({
url: 'http://localhost:3000/trpc',
}),
],
});
async function main() {
const user = await trpc.getUser.query('1');
console.log(user); // { id: '1', name: 'John Doe' }
const newUser = await trpc.createUser.mutation({ name: 'Jane Doe' });
console.log(newUser); // { id: '1', name: 'Jane Doe' }
}
main();