Deep Dive into tRPC
Introduction
tRPC is a modern, type-safe framework for building APIs in TypeScript. It provides end-to-end type safety by inferring types from your backend to your frontend, eliminating the need for manually written API contracts. This makes tRPC an attractive choice for developers seeking a seamless and efficient way to develop APIs without sacrificing type safety.
Core Concepts
-
Type Safety:
- tRPC ensures type safety across the entire stack, from backend to frontend. Types are inferred from the server-side code and automatically propagated to the client, ensuring consistency and reducing errors.
-
Zero Boilerplate:
- tRPC requires minimal setup and boilerplate code, allowing developers to focus more on building features rather than setting up complex configurations.
-
No Code Generation:
- Unlike some frameworks that rely on code generation, tRPC leverages TypeScript’s type inference, providing type safety without generating additional code files.
-
Flexible and Extendable:
- tRPC is designed to be flexible and can be easily integrated with existing frameworks and libraries. It supports various transport layers, making it suitable for different architectures.
Example Usage
-
Setting Up a tRPC Server:
// server.ts import { initTRPC } from '@trpc/server'; import { z } from 'zod'; const t = initTRPC.create(); const appRouter = t.router({ getUser: t.procedure .input(z.string()) .query(({ input }) => { return { id: input, name: 'John Doe' }; }), }); export type AppRouter = typeof appRouter; -
Setting Up a tRPC Client:
// client.ts import { createTRPCProxyClient, httpBatchLink } from '@trpc/client'; import type { AppRouter } from './server'; const client = createTRPCProxyClient<AppRouter>({ links: [ httpBatchLink({ url: 'http://localhost:3000/trpc', }), ], }); async function fetchUser() { const user = await client.getUser.query('123'); console.log(user); } fetchUser();
tRPC vs. REST
-
Type Safety:
- tRPC: Provides end-to-end type safety, with types inferred from backend code.
- REST: Typically requires manual type definitions and validation, often using tools like OpenAPI/Swagger for type safety.
-
Boilerplate:
- tRPC: Minimal boilerplate, with a focus on simplicity and developer experience.
- REST: Can involve significant boilerplate for defining routes, controllers, and validation.
-
Flexibility:
- tRPC: Designed for TypeScript-first development, tightly integrated with TypeScript’s type system.
- REST: Language-agnostic, widely adopted across various programming languages and ecosystems.
tRPC vs. GraphQL
-
Query Flexibility:
- tRPC: Type-safe, with endpoints defined in TypeScript. Fixed queries and mutations.
- GraphQL: Flexible queries, allowing clients to request exactly the data they need.
-
Type Safety:
- tRPC: End-to-end type safety with TypeScript, no additional schema definition needed.
- GraphQL: Requires a schema definition, often with tools like Apollo or Relay for type safety.
-
Setup and Complexity:
- tRPC: Simpler setup with less complexity, no need for a separate query language.
- GraphQL: More complex setup with a separate query language and resolver functions.
tRPC vs. gRPC
-
Protocol:
- tRPC: Uses HTTP/JSON by default, but can be extended to use other transport layers.
- gRPC: Uses HTTP/2 with Protocol Buffers, providing efficient binary serialization.
-
Type Safety:
- tRPC: Provides end-to-end type safety with TypeScript.
- gRPC: Provides type safety using Protocol Buffers, but requires a separate .proto file.
-
Streaming:
- tRPC: Does not natively support streaming, focused on request/response model.
- gRPC: Supports bidirectional streaming, ideal for real-time data exchange.
Use Cases
-
Single-Page Applications (SPAs):
- tRPC is ideal for SPAs built with TypeScript, where end-to-end type safety can significantly improve development speed and reduce errors.
-
Microservices:
- tRPC can be used to create type-safe APIs for microservices, ensuring consistency across service boundaries.
-
Full-Stack TypeScript Applications:
- tRPC shines in full-stack TypeScript applications, where type inference can be leveraged to maintain consistency and reduce boilerplate.
Summary
tRPC offers a modern, type-safe approach to building APIs in TypeScript, providing end-to-end type safety, minimal boilerplate, and flexibility. It stands out from REST, GraphQL, and gRPC by leveraging TypeScript’s type system to ensure consistency across the entire stack. While REST and GraphQL offer language-agnostic solutions and query flexibility, tRPC excels in environments where TypeScript is the primary language, offering a streamlined and efficient development experience.