🌐 Detecting your location…
📢 Advertisement — Configure AdSense in Appearance → Customize → AdSense Settings

دليل tRPC الكامل 2026: واجهات برمجة التطبيقات الآمنة من النوع مع Next.js واستعلام React

⏱️4 min read  ·  684 words

tRPC هي طبقة واجهة برمجة التطبيقات (API) الآمنة من النوع الشامل والتي تلغي الحاجة إلى عقود واجهة برمجة التطبيقات (API)، وإنشاء التعليمات البرمجية، وتكرار الكتابة بين الواجهة الخلفية والواجهة الأمامية لـ TypeScript. في عام 2026، أصبح الإصدار 11 من tRPC مع تكامل React Query ودعم Next.js App Router هو المعيار لتطبيقات TypeScript الكاملة. يغطي هذا الدليل كل شيء بدءًا من الإعداد وحتى أنماط الإنتاج.

لماذا tRPC؟

  • عقد صفر 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 };

استخدام العميل في React

// 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} />;
}

يعد tRPC في عام 2026 هو المعيار الذهبي لسلامة نوع TypeScript الكامل. يعد تحسين DX مثيرًا – يقوم IDE الخاص بك بإكمال وسيطات واجهة برمجة التطبيقات (API) تلقائيًا وإرجاع الأنواع دون أي خطوة لإنشاء التعليمات البرمجية. بالاشتراك مع Zod للتحقق من صحة الإدخال وNext.js App Router، ينشئ tRPC أضيق تجربة ممكنة لـ TypeScript كاملة المكدس. استخدمه لأي مشروع حيث يتم استخدام TypeScript على كل من العميل والخادم.

✍️ Leave a Comment

Your email address will not be published. Required fields are marked *

🌐 Read in:🇬🇧 English🇩🇪 Deutsch🇧🇷 Português🇸🇦 العربية🇮🇳 हिन्दी🇧🇩 বাংলা