Next.js

API Routes في Next.js — دليل شامل 2026

📅 2026-11-16⏱ 10 دقائق قراءة
في المقال السابق، تعلمت جلب البيانات. الآن سنتعلم **API Routes** — لبناء **Backend كامل** داخل Next.js. في هذا الدليل العملي، سنأخذك خطوة بخطوة لفهم API Routes، مع تمارين وحلول. ## ما هي API Routes؟ **API Routes** هي **نقاط نهاية (Endpoints)** تبنيها داخل Next.js، دون الحاجة لسيرفر منفصل. **الفائدة:** - ✅ نفس المشروع (Frontend + Backend). - ✅ نشر واحد. - ✅ TypeScript مشترك. - ✅ لا CORS. **متى تستخدمها؟** - **عندما تحتاج API** لتطبيقك. - **عندما تريد دمج البيانات** من مصادر متعددة. - **عندما تحتاج التحقق من البيانات** قبل الإرسال. - **عندما تريد حماية API Keys.** ## Route Handlers في App Router، تُسمى **Route Handlers** وتوضع في ملف `route.ts`. <table> <thead> <tr> <th>المسار</th> <th>الملف</th> <th>الرابط</th> </tr> </thead> <tbody> <tr> <td>API أساسي</td> <td><code>app/api/route.ts</code></td> <td><code>/api</code></td> </tr> <tr> <td>API للمستخدمين</td> <td><code>app/api/users/route.ts</code></td> <td><code>/api/users</code></td> </tr> <tr> <td>API للمستخدم الواحد</td> <td><code>app/api/users/[id]/route.ts</code></td> <td><code>/api/users/1</code></td> </tr> <tr> <td>API للمقالات</td> <td><code>app/api/posts/route.ts</code></td> <td><code>/api/posts</code></td> </tr> </tbody> </table> ## أول API **`app/api/hello/route.ts`:** ```tsx import { NextResponse } from "next/server"; export async function GET() { return NextResponse.json({ message: "مرحباً من Next.js API!", timestamp: new Date().toISOString(), }); } ``` **الاختبار:** ``` GET http://localhost:3000/api/hello ``` **النتيجة:** ```json { "message": "مرحباً من Next.js API!", "timestamp": "2026-11-16T10:30:00.000Z" } ``` **🎉 مبروك! بنيت أول API!** ## طرق HTTP **`app/api/users/route.ts`:** ```tsx import { NextResponse } from "next/server"; // GET /api/users export async function GET() { return NextResponse.json([ { id: 1, name: "أحمد" }, { id: 2, name: "محمد" }, ]); } // POST /api/users export async function POST(request: Request) { const body = await request.json(); return NextResponse.json( { success: true, user: body }, { status: 201 } ); } // PUT /api/users export async function PUT(request: Request) { const body = await request.json(); return NextResponse.json({ success: true, user: body }); } // DELETE /api/users export async function DELETE() { return NextResponse.json({ success: true }); } // PATCH /api/users export async function PATCH(request: Request) { const body = await request.json(); return NextResponse.json({ success: true, patch: body }); } // HEAD / OPTIONS (تلقائي) ``` ## قراءة الطلبات ### 1. قراءة Body (JSON) ```tsx export async function POST(request: Request) { const body = await request.json(); return NextResponse.json({ received: body }); } ``` ### 2. قراءة Body (Form) ```tsx export async function POST(request: Request) { const formData = await request.formData(); const name = formData.get("name") as string; return NextResponse.json({ name }); } ``` ### 3. قراءة Query Parameters ```tsx export async function GET(request: Request) { const { searchParams } = new URL(request.url); const query = searchParams.get("q"); const limit = searchParams.get("limit"); return NextResponse.json({ query, limit }); } ``` **الاختبار:** `/api/search?q=react&limit=5` ### 4. قراءة Route Parameters **`app/api/users/[id]/route.ts`:** ```tsx export async function GET( request: Request, { params }: { params: Promise<{ id: string }> } ) { const { id } = await params; return NextResponse.json({ id, name: `المستخدم ${id}` }); } ``` **⚠️ لاحظ:** في Next.js 15، `params` هو Promise. ### 5. قراءة Headers ```tsx export async function GET(request: Request) { const auth = request.headers.get("authorization"); return NextResponse.json({ auth }); } ``` ## إرسال الاستجابات ### 1. JSON ```tsx return NextResponse.json({ message: "مرحباً" }); ``` ### 2. مع Status Code ```tsx return NextResponse.json( { error: "غير موجود" }, { status: 404 } ); ``` ### 3. مع Headers ```tsx return NextResponse.json( { message: "مرحباً" }, { headers: { "Cache-Control": "no-store", "X-Custom-Header": "value", }, } ); ``` ### 4. نصوص ```tsx return new Response("نص عادي", { headers: { "Content-Type": "text/plain; charset=utf-8" }, }); ``` ### 5. إعادة توجيه ```tsx import { redirect } from "next/navigation"; export async function GET() { redirect("/"); } ``` ## أكواد الحالة <table> <thead> <tr> <th>الكود</th> <th>المعنى</th> <th>الاستخدام</th> </tr> </thead> <tbody> <tr> <td><strong>200</strong></td> <td>OK</td> <td>نجاح</td> </tr> <tr> <td><strong>201</strong></td> <td>Created</td> <td>إنشاء</td> </tr> <tr> <td><strong>204</strong></td> <td>No Content</td> <td>حذف</td> </tr> <tr> <td><strong>400</strong></td> <td>Bad Request</td> <td>طلب خاطئ</td> </tr> <tr> <td><strong>401</strong></td> <td>Unauthorized</td> <td>غير مصرح</td> </tr> <tr> <td><strong>403</strong></td> <td>Forbidden</td> <td>ممنوع</td> </tr> <tr> <td><strong>404</strong></td> <td>Not Found</td> <td>غير موجود</td> </tr> <tr> <td><strong>500</strong></td> <td>Internal Server Error</td> <td>خطأ في السيرفر</td> </tr> </tbody> </table> ## مثال عملي: CRUD للمستخدمين **`app/api/users/route.ts`:** ```tsx import { NextResponse } from "next/server"; let users = [ { id: 1, name: "أحمد", email: "[email protected]" }, { id: 2, name: "محمد", email: "[email protected]" }, ]; // GET /api/users export async function GET() { return NextResponse.json(users); } // POST /api/users export async function POST(request: Request) { const body = await request.json(); if (!body.name || !body.email) { return NextResponse.json( { error: "الاسم والبريد مطلوبان" }, { status: 400 } ); } const newUser = { id: Date.now(), name: body.name, email: body.email, }; users.push(newUser); return NextResponse.json(newUser, { status: 201 }); } ``` **`app/api/users/[id]/route.ts`:** ```tsx import { NextResponse } from "next/server"; let users = [ { id: 1, name: "أحمد", email: "[email protected]" }, { id: 2, name: "محمد", email: "[email protected]" }, ]; // GET /api/users/:id export async function GET( request: Request, { params }: { params: Promise<{ id: string }> } ) { const { id } = await params; const user = users.find((u) => u.id === parseInt(id)); if (!user) { return NextResponse.json( { error: "المستخدم غير موجود" }, { status: 404 } ); } return NextResponse.json(user); } // PUT /api/users/:id export async function PUT( request: Request, { params }: { params: Promise<{ id: string }> } ) { const { id } = await params; const body = await request.json(); const index = users.findIndex((u) => u.id === parseInt(id)); if (index === -1) { return NextResponse.json( { error: "المستخدم غير موجود" }, { status: 404 } ); } users[index] = { ...users[index], ...body }; return NextResponse.json(users[index]); } // DELETE /api/users/:id export async function DELETE( request: Request, { params }: { params: Promise<{ id: string }> } ) { const { id } = await params; const index = users.findIndex((u) => u.id === parseInt(id)); if (index === -1) { return NextResponse.json( { error: "المستخدم غير موجود" }, { status: 404 } ); } users.splice(index, 1); return new NextResponse(null, { status: 204 }); } ``` ## التحقق من البيانات ```tsx export async function POST(request: Request) { const body = await request.json(); const errors = []; if (!body.name || body.name.length < 2) { errors.push("الاسم يجب أن يكون حرفين على الأقل"); } if (!body.email || !body.email.includes("@")) { errors.push("البريد غير صحيح"); } if (body.age && (body.age < 18 || body.age > 100)) { errors.push("العمر يجب أن يكون بين 18 و 100"); } if (errors.length > 0) { return NextResponse.json( { errors }, { status: 400 } ); } // ... إنشاء المستخدم } ``` ## استخدام API من Client ### 1. استخدام fetch ```tsx "use client"; import { useState, useEffect } from "react"; export default function UsersList() { const [users, setUsers] = useState([]); useEffect(() => { fetch("/api/users") .then((res) => res.json()) .then(setUsers); }, []); return ( <ul> {users.map((u) => ( <li key={u.id}>{u.name}</li> ))} </ul> ); } ``` ### 2. إرسال POST ```tsx "use client"; async function createUser(name: string, email: string) { const res = await fetch("/api/users", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ name, email }), }); const data = await res.json(); return data; } ``` ## مثال: API للبحث **`app/api/search/route.ts`:** ```tsx import { NextResponse } from "next/server"; const articles = [ { id: 1, title: "تعلم Next.js", category: "برمجة" }, { id: 2, title: "تعلم React", category: "برمجة" }, { id: 3, title: "تعلم TypeScript", category: "برمجة" }, ]; export async function GET(request: Request) { const { searchParams } = new URL(request.url); const q = searchParams.get("q") || ""; const results = articles.filter((article) => article.title.toLowerCase().includes(q.toLowerCase()) ); return NextResponse.json({ query: q, count: results.length, results, }); } ``` **الاختبار:** `/api/search?q=react` ## تمارين عملية ### تمرين 1: API بسيط أنشئ `/api/hello` يعيد ترحيباً. **الحل:** ```tsx import { NextResponse } from "next/server"; export async function GET() { return NextResponse.json({ message: "مرحباً" }); } ``` ### تمرين 2: GET مع Query أنشئ API يقرأ `?name=`. **الحل:** ```tsx export async function GET(request: Request) { const { searchParams } = new URL(request.url); const name = searchParams.get("name") || "زائر"; return NextResponse.json({ message: `مرحباً ${name}` }); } ``` ### تمرين 3: POST أنشئ API يستقبل JSON. **الحل:** ```tsx export async function POST(request: Request) { const body = await request.json(); return NextResponse.json({ received: body }, { status: 201 }); } ``` ### تمرين 4: CRUD كامل أنشئ CRUD للمقالات. **الحل:** ```tsx // app/api/posts/route.ts let posts = []; export async function GET() { return NextResponse.json(posts); } export async function POST(request: Request) { const body = await request.json(); const post = { id: Date.now(), ...body }; posts.push(post); return NextResponse.json(post, { status: 201 }); } ``` ### تمرين 5: مسار ديناميكي أنشئ `/api/users/[id]`. **الحل:** ```tsx export async function GET( request: Request, { params }: { params: Promise<{ id: string }> } ) { const { id } = await params; return NextResponse.json({ id }); } ``` ### تمرين 6: التحقق أضف تحققاً للبيانات. **الحل:** ```tsx if (!body.email?.includes("@")) { return NextResponse.json( { error: "بريد غير صحيح" }, { status: 400 } ); } ``` ### تمرين 7: حماية API أضف تحقق من Authorization. **الحل:** ```tsx export async function POST(request: Request) { const auth = request.headers.get("authorization"); if (auth !== "Bearer secret-token") { return NextResponse.json( { error: "غير مصرح" }, { status: 401 } ); } // ... } ``` ### تمرين 8: API متكامل ابنِ API كامل مع CRUD + تحقق + حماية. **الحل:** (راجع المثال الكامل أعلاه) ## حل المشاكل الشائعة ### 🔴 المشكلة 1: API لا يعمل في Client **السبب:** استخدام URL غير كامل. **الحل:** استخدم URL نسبي: ```tsx fetch("/api/users"); // ✅ ``` ### 🔴 المشكلة 2: `request.json()` يفشل **السبب:** Body فارغ أو غير JSON. **الحل:** ```tsx try { const body = await request.json(); } catch { return NextResponse.json({ error: "JSON غير صحيح" }, { status: 400 }); } ``` ### 🔴 المشكلة 3: CORS **السبب:** الطلب من نطاق مختلف. **الحل:** أضف headers: ```tsx return NextResponse.json(data, { headers: { "Access-Control-Allow-Origin": "*", }, }); ``` ### 🔴 المشكلة 4: API Routes لا تعمل مع `output: 'export'` **السبب:** التصدير الثابت لا يدعم API Routes. **الحل:** استخدم Vercel أو Firebase Functions. ### 🔴 المشكلة 5: `params` غير متاح **السبب:** في Next.js 15، `params` هو Promise. **الحل:** ```tsx { params }: { params: Promise<{ id: string }> } // ... const { id } = await params; ``` ## جدول دوال API <table> <thead> <tr> <th>الدالة</th> <th>الوظيفة</th> </tr> </thead> <tbody> <tr> <td><code>NextResponse.json()</code></td> <td>إرسال JSON</td> </tr> <tr> <td><code>request.json()</code></td> <td>قراءة JSON</td> </tr> <tr> <td><code>request.formData()</code></td> <td>قراءة Form</td> </tr> <tr> <td><code>request.headers.get()</code></td> <td>قراءة Header</td> </tr> <tr> <td><code>new URL(request.url)</code></td> <td>قراءة Query</td> </tr> <tr> <td><code>new Response()</code></td> <td>استجابة مخصصة</td> </tr> <tr> <td><code>redirect()</code></td> <td>إعادة توجيه</td> </tr> </tbody> </table> ## قائمة تحقق نهائية <table> <thead> <tr> <th>المهمة</th> <th>الحالة</th> </tr> </thead> <tbody> <tr> <td>فهم Route Handlers</td> <td>⬜</td> </tr> <tr> <td>GET و POST</td> <td>⬜</td> </tr> <tr> <td>قراءة Body و Query</td> <td>⬜</td> </tr> <tr> <td>المسارات الديناميكية</td> <td>⬜</td> </tr> <tr> <td>التحقق من البيانات</td> <td>⬜</td> </tr> <tr> <td>حماية API</td> <td>⬜</td> </tr> <tr> <td>حل التمارين الثمانية</td> <td>⬜</td> </tr> </tbody> </table> ## ماذا بعد هذا المقال؟ الآن بعد أن أتقنت API Routes، أنت جاهز للمقال التالي: 1. **Styling** — Tailwind و CSS. 2. **Authentication** — المصادقة. 3. **Deployment** — النشر. ## الخلاصة في هذا المقال، تعلمت: - ✅ ما هي API Routes. - ✅ Route Handlers. - ✅ طرق HTTP. - ✅ قراءة الطلبات. - ✅ إرسال الاستجابات. - ✅ CRUD كامل. - ✅ التحقق من البيانات. - ✅ حل 8 تمارين عملية. **تذكر:** API Routes تجعل Next.js **إطاراً كاملاً** — Frontend و Backend.