tRPC হল এন্ড-টু-এন্ড টাইপ-সেফ API লেয়ার যা আপনার TypeScript ব্যাকএন্ড এবং ফ্রন্টএন্ডের মধ্যে API চুক্তি, কোড জেনারেশন এবং টাইপ ডুপ্লিকেশনের প্রয়োজনীয়তা দূর করে। 2026 সালে, React Query ইন্টিগ্রেশন এবং Next.js অ্যাপ রাউটার সাপোর্ট সহ tRPC v11 ফুল-স্ট্যাক TypeScript অ্যাপ্লিকেশনের জন্য আদর্শ হয়ে উঠেছে। এই নির্দেশিকা সেটআপ থেকে উত্পাদন নিদর্শন সবকিছু কভার.
📋 Table of Contents
কেন টিআরপিসি?
- জিরো API চুক্তি– ব্যাকএন্ড প্রকারগুলি ফ্রন্টএন্ডে স্বয়ংক্রিয়ভাবে উপলব্ধ
- কোন কোড জেনারেশন নেই— কম্পাইলের সময় অনুমানকৃত প্রকার, তৈরি করা হয়নি
- সম্পূর্ণ টাইপস্ক্রিপ্ট— API কল, আর্গুমেন্ট এবং রিটার্ন প্রকারের জন্য স্বয়ংসম্পূর্ণ
- প্রতিক্রিয়া ক্যোয়ারী অন্তর্নির্মিত— ক্যাশিং, লোডিং স্টেট, স্বয়ংক্রিয়ভাবে কাজ রিফেচ করা
- ফাংশন কল হিসাবে একই DX —
trpc.user.getById.useQuery(1)
Next.js অ্যাপ রাউটার দিয়ে সেটআপ করুন
npm install @trpc/server @trpc/client @trpc/react-query @trpc/next
npm install @tanstack/react-query
npm install zod
src/
server/
api/
trpc.ts — tRPC base config
root.ts — root router
routers/
user.ts
post.ts
trpc/
react.tsx — client setup
server.ts — server-side caller
সার্ভার সেটআপ
// server/api/trpc.ts
import { initTRPC, TRPCError } from '@trpc/server';
import { ZodError } from 'zod';
// Context type — available in all procedures
export interface Context {
userId: string | null;
db: PrismaClient;
}
const t = initTRPC.context<Context>().create({
errorFormatter({ shape, error }) {
return {
...shape,
data: {
...shape.data,
zodError: error.cause instanceof ZodError ? error.cause.flatten() : null,
},
};
},
});
export const router = t.router;
export const publicProcedure = t.procedure;
// Auth middleware
const isAuthenticated = t.middleware(({ ctx, next }) => {
if (!ctx.userId) {
throw new TRPCError({ code: 'UNAUTHORIZED' });
}
return next({ ctx: { ...ctx, userId: ctx.userId } });
});
export const protectedProcedure = t.procedure.use(isAuthenticated);
// Rate limiting middleware
const withRateLimit = t.middleware(async ({ ctx, next }) => {
const key = `ratelimit:${ctx.userId ?? 'anonymous'}`;
const count = await redis.incr(key);
if (count === 1) await redis.expire(key, 60);
if (count > 100) throw new TRPCError({ code: 'TOO_MANY_REQUESTS' });
return next();
});
export const rateLimitedProcedure = protectedProcedure.use(withRateLimit);
রাউটার
// server/api/routers/user.ts
import { z } from 'zod';
import { router, publicProcedure, protectedProcedure } from '../trpc';
export const userRouter = router({
// Query — get data
getById: publicProcedure
.input(z.number().int().positive())
.query(async ({ ctx, input }) => {
const user = await ctx.db.user.findUnique({ where: { id: input } });
if (!user) throw new TRPCError({ code: 'NOT_FOUND', message: `User ${input} not found` });
return user;
}),
// Query with pagination
list: publicProcedure
.input(z.object({
page: z.number().default(1),
limit: z.number().max(100).default(20),
search: z.string().optional(),
}))
.query(async ({ ctx, input }) => {
const { page, limit, search } = input;
const [users, total] = await ctx.db.$transaction([
ctx.db.user.findMany({
where: search ? { name: { contains: search, mode: 'insensitive' } } : undefined,
skip: (page - 1) * limit,
take: limit,
}),
ctx.db.user.count(),
]);
return { users, total, page, limit };
}),
// Mutation — create/update/delete
create: protectedProcedure
.input(z.object({
name: z.string().min(2).max(50),
email: z.string().email(),
}))
.mutation(async ({ ctx, input }) => {
return ctx.db.user.create({ data: input });
}),
update: protectedProcedure
.input(z.object({
id: z.number(),
name: z.string().optional(),
email: z.string().email().optional(),
}))
.mutation(async ({ ctx, input }) => {
const { id, ...data } = input;
return ctx.db.user.update({ where: { id }, data });
}),
// Subscription — real-time
onUserCreated: protectedProcedure.subscription(({ ctx }) => {
return observable<User>((emit) => {
const unsub = eventEmitter.on('user.created', (user) => {
emit.next(user);
});
return () => unsub();
});
}),
});
রুট রাউটার
// server/api/root.ts
import { router } from './trpc';
import { userRouter } from './routers/user';
import { postRouter } from './routers/post';
export const appRouter = router({
user: userRouter,
post: postRouter,
});
export type AppRouter = typeof appRouter;
Next.js অ্যাপ রাউটার হ্যান্ডলার
// app/api/trpc/[trpc]/route.ts
import { fetchRequestHandler } from '@trpc/server/adapters/fetch';
import { appRouter } from '@/server/api/root';
import { createContext } from '@/server/api/context';
const handler = (req: Request) =>
fetchRequestHandler({
endpoint: '/api/trpc',
req,
router: appRouter,
createContext,
});
export { handler as GET, handler as POST };
প্রতিক্রিয়ায় ক্লায়েন্টের ব্যবহার
// trpc/react.tsx
'use client';
import { createTRPCReact } from '@trpc/react-query';
import type { AppRouter } from '@/server/api/root';
export const trpc = createTRPCReact<AppRouter>();
// components/UserList.tsx
'use client';
import { trpc } from '@/trpc/react';
export function UserList() {
const { data, isLoading, error } = trpc.user.list.useQuery({
page: 1,
limit: 20,
search: 'alice',
});
const createUser = trpc.user.create.useMutation({
onSuccess: () => {
utils.user.list.invalidate(); // refetch list
},
});
const utils = trpc.useUtils();
if (isLoading) return <Spinner />;
if (error) return <Error message={error.message} />;
return (
<div>
{data?.users.map(user => <UserCard key={user.id} user={user} />)}
<button onClick={() => createUser.mutate({ name: 'Bob', email: 'bob@example.com' })}>
{createUser.isPending ? 'Creating...' : 'Add User'}
</button>
</div>
);
}
// Server component usage (no hook)
import { api } from '@/trpc/server';
export default async function Page() {
const users = await api.user.list.query({ page: 1, limit: 10 });
return <UserList initialData={users} />;
}
2026 সালে tRPC হল ফুল-স্ট্যাক TypeScript ধরনের নিরাপত্তার জন্য সোনার মান। DX উন্নতি নাটকীয় — আপনার IDE স্বয়ংসম্পূর্ণ API আর্গুমেন্ট এবং রিটার্ন টাইপ কোনো কোড তৈরির ধাপ ছাড়াই। ইনপুট যাচাইকরণ এবং Next.js অ্যাপ রাউটারের জন্য Zod-এর সাথে মিলিত, tRPC সম্ভাব্য সবচেয়ে টাইট TypeScript ফুল-স্ট্যাক অভিজ্ঞতা তৈরি করে। যেকোন প্রজেক্টের জন্য এটি ব্যবহার করুন যেখানে ক্লায়েন্ট এবং সার্ভার উভয়েই TypeScript ব্যবহার করা হয়।
🔗 Share this article
✍️ Leave a Comment