Episode ini menghidupkan API tRPC lewat server nyata: server standalone atau Express, adapter untuk Next.js App Router, dan client tRPC di React. Kalian akan menjalankan request pertama dan merasakan autocompletion type-safe dari editor.

API di episode 3 masih berupa kode yang dipanggil langsung. Sekarang saatnya menghidupkannya: melayani router lewat server nyata dan mengkonsumsinya dari client. Di episode 4 kalian akan menyiapkan server dengan dua cara — standalone/Express dan Next.js App Router — lalu membuat client tRPC di frontend React.
Di akhir episode, kalian akan menjalankan request pertama dan melihat langsung autocompletion type-safe: editor tahu nama procedure, bentuk input, dan bentuk response tanpa dokumentasi terpisah.
Cara termudah untuk development lokal adalah server standalone:
import { createHTTPServer } from "@trpc/server/adapters/standalone";
import { appRouter } from "./routers";
const server = createHTTPServer({
router: appRouter,
createContext: () => ({}),
});
server.listen(3000);Jalankan dan verifikasi endpoint dengan curl:
npx tsx src/server/index.ts
curl "http://localhost:3000/trpc/user.byId?input=%7B%22id%22%3A1%7D"Endpoint default adalah /trpc. Input dikirim sebagai JSON yang di-encode di query parameter — itulah mengapa URL di atas terlihat kompleks. Client tRPC akan menangani encoding ini secara otomatis.
Jika project sudah memakai Express, gunakan createExpressMiddleware:
npm install express cors
npm install --save-dev @types/express @types/corsimport express from "express";
import cors from "cors";
import { createExpressMiddleware } from "@trpc/server/adapters/express";
import { appRouter } from "./routers";
const app = express();
app.use(cors());
app.use(
"/trpc",
createExpressMiddleware({
router: appRouter,
createContext: () => ({}),
}),
);
app.listen(3000, () => console.log("Server berjalan di port 3000"));createExpressMiddleware({ router, createContext }) mengembalikan middleware Express standar, jadi tetap bisa dikombinasikan dengan route lain. Fastify juga punya adapter serupa bernama fastifyTRPCPlugin — pola-nya identik.
Di Next.js App Router, tRPC dilayani lewat sebuah route handler:
import { fetchRequestHandler } from "@trpc/server/adapters/fetch";
import { appRouter } from "@/server/routers";
const handler = (req: Request) =>
fetchRequestHandler({
endpoint: "/api/trpc",
req,
router: appRouter,
createContext: () => ({}),
});
export { handler as GET, handler as POST };Dengan file ini, seluruh procedure tRPC tersedia di /api/trpc tanpa perlu menulis route handler per procedure. Folder dinamis [trpc] menangkap path procedure apapun.
Untuk React, pasang paket tambahan:
npm install @trpc/react-query @tanstack/react-queryBuat client di file tersendiri:
import { createTRPCReact } from "@trpc/react-query";
import { httpBatchLink } from "@trpc/client";
import type { AppRouter } from "@/server/routers";
export const trpc = createTRPCReact<AppRouter>();
export const getBaseUrl = () =>
process.env.NEXT_PUBLIC_BASE_URL ?? "http://localhost:3000";Kemudian bungkus aplikasi dengan QueryClientProvider dan trpc.Provider:
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { httpBatchLink } from "@trpc/client";
import { trpc, getBaseUrl } from "./trpc";
const queryClient = new QueryClient();
const trpcClient = trpc.createClient({
links: [httpBatchLink({ url: `${getBaseUrl()}/api/trpc` })],
});
export function Providers({ children }: { children: React.ReactNode }) {
return (
<trpc.Provider client={trpcClient} queryClient={queryClient}>
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
</trpc.Provider>
);
}trpc.createClient({ links: [httpBatchLink(...)] }) membuat instance client yang terhubung ke endpoint /api/trpc.
Sekarang procedure tRPC bisa dipanggil seperti hook biasa:
"use client";
import { trpc } from "@/lib/trpc";
export default function Profile({ id }: { id: number }) {
const { data, isLoading } = trpc.user.byId.useQuery({ id });
if (isLoading) return <p>Memuat...</p>;
return <h1>Halo, {data?.nama}</h1>;
}Perhatikan: trpc.user.byId.useQuery({ id }) dijamin ada karena prosedur user.byId terdefinisi di server. Salah ketik nama procedure atau mengirim input yang salah bentuk akan menghasilkan error TypeScript di editor — inilah autocompletion type-safe yang menjadi daya tarik utama tRPC.
Untuk operasi tulis, trpc.user.create.useMutation() juga tersedia dengan output bertipe lengkap — cocok untuk form dan aksi lain yang mengubah data.
Warning
Ingat kembali pola di episode 2: createTRPCProxyClient untuk kode non-React, createTRPCReact untuk hooks. Jangan mencampur keduanya di tempat yang salah — proxy client tidak menyediakan hook useQuery.
Episode 4 menghubungkan dua sisi tRPC: server yang melayani router lewat standalone, Express, atau Next.js App Router, dan client React yang memakainya lewat hooks dengan autocompletion penuh.
Inti yang harus dibawa pulang:
createHTTPServer untuk server standalone; createExpressMiddleware untuk Express.fetchRequestHandler di route handler /api/trpc.createContext menyediakan data per request, seperti session.@trpc/react-query dan @tanstack/react-query untuk React.trpc.Provider membungkus aplikasi dan menyambungkan query client.useQuery dan useMutation memberi autocompletion type-safe.Di episode 5 selanjutnya kita akan membahas input validation, error handling & response types — memperdalam validasi zod dan superstruct, mengenal TRPCError dan formatError, pemetaan HTTP status, serta fallback default values untuk response.