tRPC: Buat API yang Sepenuhnya Type-Safe Tanpa Tulis Satu Baris Schema
tRPC adalah cara paling elegan untuk komunikasi client-server di Next.js. Tidak perlu REST endpoints, tidak perlu GraphQL schema — cukup TypeScript, dan kedua sisi otomatis sinkron.
Muhamad Putra Aulia Hidayat
tRPC: End-to-End Type Safety Tanpa Overhead
Bayangkan bisa call fungsi server dari client seperti memanggil fungsi lokal — lengkap dengan autocomplete, type checking, dan error handling yang penuh. Itu yang tRPC tawarkan.
Masalah yang Diselesaikan tRPC
// Tanpa tRPC - tidak ada type safety end-to-end
// Server
app.get("/api/users/:id", async (req, res) => {
const user = await getUser(req.params.id)
res.json(user) // Tipe? Tidak jelas di client
})
// Client
const response = await fetch("/api/users/123")
const user = await response.json() // Tipe: any. Harus cast manual
// Dengan tRPC - full type safety
// Server
const userRouter = router({
getById: publicProcedure
.input(z.string().uuid())
.query(async ({ input }) => {
return getUser(input) // Return type otomatis di-infer
})
})
// Client - autocomplete penuh, type-safe!
const user = await trpc.user.getById.query("550e8400-...")
// user: User (type otomatis dari server)
Setup di Next.js
npm install @trpc/server @trpc/client @trpc/react-query @tanstack/react-query zod
// server/trpc.ts
import { initTRPC } from "@trpc/server"
import { z } from "zod"
const t = initTRPC.create()
export const router = t.router
export const publicProcedure = t.procedure
// Untuk protected routes
export const protectedProcedure = t.procedure.use(async ({ ctx, next }) => {
if (!ctx.session?.user) {
throw new TRPCError({ code: "UNAUTHORIZED" })
}
return next({ ctx: { user: ctx.session.user } })
})
// server/routers/products.ts
import { router, publicProcedure, protectedProcedure } from "../trpc"
import { z } from "zod"
export const productsRouter = router({
list: publicProcedure
.input(z.object({
page: z.number().min(1).default(1),
limit: z.number().min(1).max(100).default(20),
category: z.string().optional()
}))
.query(async ({ input }) => {
const { page, limit, category } = input
return db.products.findMany({
where: category ? { category } : undefined,
skip: (page - 1) * limit,
take: limit
})
}),
getById: publicProcedure
.input(z.string().uuid())
.query(async ({ input }) => {
const product = await db.products.findUnique({ where: { id: input } })
if (!product) throw new TRPCError({ code: "NOT_FOUND" })
return product
}),
create: protectedProcedure
.input(z.object({
name: z.string().min(3),
price: z.number().positive(),
stock: z.number().int().min(0)
}))
.mutation(async ({ input, ctx }) => {
return db.products.create({
data: { ...input, createdById: ctx.user.id }
})
}),
})
// server/routers/_app.ts
import { router } from "../trpc"
import { productsRouter } from "./products"
import { usersRouter } from "./users"
import { ordersRouter } from "./orders"
export const appRouter = router({
products: productsRouter,
users: usersRouter,
orders: ordersRouter,
})
export type AppRouter = typeof appRouter
Pakai di React Component
"use client"
import { trpc } from "@/lib/trpc"
export function ProductList() {
const { data, isLoading } = trpc.products.list.useQuery({
page: 1,
limit: 20
})
const createProduct = trpc.products.create.useMutation({
onSuccess: () => {
// Invalidate dan refetch
trpc.products.list.invalidate()
}
})
if (isLoading) return <div>Loading...</div>
return (
<div>
{data?.map(product => (
<div key={product.id}>
{product.name} - Rp {product.price.toLocaleString("id")}
</div>
))}
</div>
)
}
tRPC vs REST vs GraphQL
| Aspek | REST | GraphQL | tRPC |
|---|---|---|---|
| Type safety | Manual | Code-gen | Otomatis |
| Setup complexity | Rendah | Tinggi | Sedang |
| Fleksibilitas query | Terbatas | Tinggi | Sedang |
| Best for | Public API | Complex data graph | Full-stack TypeScript |
Kapan Pakai tRPC?
Ideal untuk: Full-stack TypeScript app di mana client dan server dalam satu codebase (Next.js monorepo).
Tidak ideal untuk: Public API yang dikonsumsi banyak client berbeda (mobile, third-party) — lebih baik REST atau GraphQL.
tRPC adalah game-changer untuk developer yang sudah all-in di TypeScript dan Next.js.
Newsletter Digital Uptime
Tips teknologi & bisnis mingguan
Bergabung dengan 2,500+ subscriber yang mendapatkan insight teknologi, tutorial development, dan tips bisnis digital langsung ke inbox mereka setiap minggu.