تعلم كيفية إنشاء نقاط نهاية API قوية باستخدام معالجات التوجيه في Next.js. يغطي هذا الدليل كل شيء بدءًا من الإعداد الأساسي إلى التقنيات المتقدمة، مع أمثلة عملية وأفضل الممارسات.
معالجات التوجيه في Next.js: دليل شامل لإنشاء نقاط نهاية API
أحدث إطار العمل Next.js ثورة في طريقة بناء تطبيقات الويب بميزاته القوية مثل العرض من جانب الخادم، وتوليد المواقع الثابتة، والآن، معالجات التوجيه (Route Handlers). توفر معالجات التوجيه طريقة مرنة وفعالة لإنشاء نقاط نهاية API مباشرة داخل تطبيق Next.js الخاص بك. يستكشف هذا الدليل مفهوم معالجات التوجيه وفوائدها وكيفية استخدامها بفعالية لبناء واجهات برمجة تطبيقات (APIs) قوية.
ما هي معالجات التوجيه في Next.js؟
معالجات التوجيه هي دوال يتم تعريفها داخل مجلد app
في مشروع Next.js لمعالجة طلبات HTTP الواردة. على عكس النهج القديم pages/api
(الذي يستخدم مسارات API)، تقدم معالجات التوجيه طريقة أكثر تبسيطًا ومرونة لتعريف نقاط نهاية API إلى جانب مكونات React الخاصة بك. هي في الأساس دوال بلا خادم (serverless functions) يتم تنفيذها على الحافة (edge) أو بيئة الخادم التي تختارها.
فكر في معالجات التوجيه على أنها المنطق الخلفي لتطبيق Next.js الخاص بك، والمسؤولة عن معالجة الطلبات، والتفاعل مع قواعد البيانات، وإرجاع الاستجابات.
فوائد استخدام معالجات التوجيه
- التجميع في مكان واحد (Colocation): تتواجد معالجات التوجيه مباشرة بجانب مكونات React الخاصة بك داخل مجلد
app
، مما يعزز التنظيم الأفضل وسهولة صيانة الكود. - دعم TypeScript: يضمن دعم TypeScript المدمج أمان الأنواع (type safety) وتحسين تجربة المطور.
- التكامل مع الوسيط (Middleware): يمكنك بسهولة دمج الوسيط (middleware) لمهام مثل المصادقة والترخيص والتحقق من صحة الطلبات.
- دعم البث (Streaming): يمكن لمعالجات التوجيه بث البيانات، مما يتيح لك إرسال الاستجابات بشكل تدريجي، وهو أمر مفيد لمجموعات البيانات الكبيرة أو العمليات طويلة الأمد.
- دوال الحافة (Edge Functions): انشر معالجات التوجيه كدوال حافة للحصول على استجابات بزمن وصول منخفض أقرب إلى المستخدمين، مع الاستفادة من شبكات توصيل المحتوى (CDNs) العالمية.
- تصميم API مبسط: توفر معالجات التوجيه واجهة برمجة تطبيقات نظيفة وبديهية للتعامل مع الطلبات والاستجابات.
- التكامل مع إجراءات الخادم (Server Actions): يسمح التكامل الوثيق مع إجراءات الخادم بالاتصال السلس بين مكونات العميل والمنطق من جانب الخادم.
إعداد مشروع Next.js الخاص بك
قبل الغوص في معالجات التوجيه، تأكد من أن لديك مشروع Next.js تم إعداده باستخدام مجلد app
. إذا كنت تبدأ مشروعًا جديدًا، فاستخدم الأمر التالي:
npx create-next-app@latest my-nextjs-app
اختر مجلد app
أثناء عملية الإعداد لتمكين نظام التوجيه الجديد.
إنشاء أول معالج توجيه لك
لنقم بإنشاء نقطة نهاية API بسيطة تعيد استجابة JSON. أنشئ مجلدًا جديدًا داخل مجلد app
، على سبيل المثال، /app/api/hello
. داخل هذا المجلد، أنشئ ملفًا باسم route.ts
(أو route.js
إذا كنت لا تستخدم TypeScript).
إليك كود أول معالج توجيه لك:
// app/api/hello/route.ts
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
return NextResponse.json({ message: 'Hello from Next.js Route Handlers!' });
}
شرح الكود:
import { NextResponse } from 'next/server';
: يستورد كائنNextResponse
، الذي يستخدم لإنشاء استجابات API.export async function GET(request: Request) { ... }
: تعرف دالة غير متزامنة تعالج طلبات GET إلى نقطة النهاية/api/hello
. يوفر المعلمrequest
الوصول إلى كائن الطلب الوارد.return NextResponse.json({ message: 'Hello from Next.js Route Handlers!' });
: تنشئ استجابة JSON مع رسالة وتعيدها باستخدامNextResponse.json()
.
الآن، يمكنك الوصول إلى نقطة النهاية هذه عن طريق الانتقال إلى /api/hello
في متصفحك أو استخدام أداة مثل curl
أو Postman
.
التعامل مع طرق HTTP المختلفة
تدعم معالجات التوجيه طرق HTTP المختلفة مثل GET و POST و PUT و DELETE و PATCH و OPTIONS. يمكنك تعريف دوال منفصلة لكل طريقة داخل نفس ملف route.ts
.
// app/api/users/route.ts
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
// Logic to retrieve all users from the database
const users = [{ id: 1, name: 'John Doe' }, { id: 2, name: 'Jane Smith' }]; // Example data
return NextResponse.json(users);
}
export async function POST(request: Request) {
const data = await request.json(); // Parse the request body as JSON
// Logic to create a new user in the database using 'data'
const newUser = { id: 3, name: data.name, email: data.email }; // Example
return NextResponse.json(newUser, { status: 201 }); // Return the new user with a 201 Created status code
}
شرح الكود:
- تسترجع دالة
GET
قائمة بالمستخدمين (محاكاة هنا) وتعيدهم كاستجابة JSON. - تقوم دالة
POST
بتحليل نص الطلب كـ JSON، وتنشئ مستخدمًا جديدًا (محاكاة)، وتعيد المستخدم الجديد مع رمز الحالة 201 Created.
الوصول إلى بيانات الطلب
يوفر كائن request
الوصول إلى معلومات مختلفة حول الطلب الوارد، بما في ذلك الترويسات (headers)، ومعلمات الاستعلام (query parameters)، ونص الطلب.
الترويسات (Headers)
يمكنك الوصول إلى ترويسات الطلب باستخدام خاصية request.headers
:
export async function GET(request: Request) {
const userAgent = request.headers.get('user-agent');
console.log('User Agent:', userAgent);
return NextResponse.json({ userAgent });
}
معلمات الاستعلام (Query Parameters)
للوصول إلى معلمات الاستعلام، يمكنك استخدام مُنشئ URL
:
export async function GET(request: Request) {
const url = new URL(request.url);
const searchParams = new URLSearchParams(url.search);
const id = searchParams.get('id');
console.log('ID:', id);
return NextResponse.json({ id });
}
نص الطلب (Request Body)
بالنسبة لطلبات POST و PUT و PATCH، يمكنك الوصول إلى نص الطلب باستخدام أساليب request.json()
أو request.text()
، اعتمادًا على نوع المحتوى.
export async function POST(request: Request) {
const data = await request.json();
console.log('Data:', data);
return NextResponse.json({ receivedData: data });
}
إرجاع الاستجابات
يستخدم كائن NextResponse
لإنشاء استجابات API. ويوفر عدة طرق لتعيين الترويسات ورموز الحالة ونصوص الاستجابة.
استجابات JSON
استخدم طريقة NextResponse.json()
لإرجاع استجابات JSON:
return NextResponse.json({ message: 'Success!', data: { name: 'John Doe' } }, { status: 200 });
استجابات نصية
استخدم مُنشئ new Response()
لإرجاع استجابات نصية عادية:
return new Response('Hello, world!', { status: 200, headers: { 'Content-Type': 'text/plain' } });
إعادة التوجيه (Redirects)
استخدم NextResponse.redirect()
لإعادة توجيه المستخدمين إلى عنوان URL مختلف:
import { redirect } from 'next/navigation';
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
return NextResponse.redirect(new URL('/new-location', request.url));
}
تعيين الترويسات (Headers)
يمكنك تعيين ترويسات مخصصة باستخدام خيار headers
في NextResponse.json()
أو new Response()
:
return NextResponse.json({ message: 'Success!' }, { status: 200, headers: { 'Cache-Control': 'no-cache' } });
التكامل مع الوسيط (Middleware)
يسمح لك الوسيط (Middleware) بتشغيل كود قبل معالجة الطلب بواسطة معالج التوجيه الخاص بك. هذا مفيد للمصادقة والترخيص والتسجيل وغيرها من الاهتمامات الشاملة (cross-cutting concerns).
لإنشاء وسيط، أنشئ ملفًا باسم middleware.ts
(أو middleware.js
) في مجلد app
أو أي مجلد فرعي. سيتم تطبيق الوسيط على جميع المسارات داخل ذلك المجلد ومجلداته الفرعية.
// app/middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const token = request.cookies.get('auth-token');
if (!token) {
return NextResponse.redirect(new URL('/login', request.url));
}
return NextResponse.next();
}
export const config = {
matcher: ['/protected/:path*'], // Apply this middleware to paths starting with /protected/
};
شرح الكود:
- تتحقق دالة
middleware
من وجود رمز مصادقة في ملفات تعريف الارتباط (cookies) الخاصة بالطلب. - إذا كان الرمز مفقودًا، فإنه يعيد توجيه المستخدم إلى صفحة تسجيل الدخول.
- وإلا، فإنه يسمح للطلب بالانتقال إلى معالج التوجيه.
- يحدد كائن
config
أن هذا الوسيط يجب أن يطبق فقط على المسارات التي تبدأ بـ/protected/
.
معالجة الأخطاء
تعتبر معالجة الأخطاء بشكل صحيح أمرًا بالغ الأهمية لبناء واجهات برمجة تطبيقات قوية. يمكنك استخدام كتل try...catch
لمعالجة الاستثناءات وإرجاع استجابات خطأ مناسبة.
export async function GET(request: Request) {
try {
// Simulate an error
throw new Error('Something went wrong!');
} catch (error: any) {
console.error('Error:', error);
return NextResponse.json({ error: error.message }, { status: 500 });
}
}
شرح الكود:
- تلتقط كتلة
try...catch
أي استثناءات تحدث داخل معالج التوجيه. - في كتلة
catch
، يتم تسجيل الخطأ، وإرجاع استجابة خطأ برمز الحالة 500 Internal Server Error.
الاستجابات المتدفقة (Streaming Responses)
تدعم معالجات التوجيه الاستجابات المتدفقة، مما يسمح لك بإرسال البيانات بشكل تدريجي إلى العميل. هذا مفيد بشكل خاص لمجموعات البيانات الكبيرة أو العمليات طويلة الأمد.
import { Readable } from 'stream';
import { NextResponse } from 'next/server';
async function* generateData() {
for (let i = 0; i < 10; i++) {
await new Promise(resolve => setTimeout(resolve, 500)); // Simulate delay
yield `Data chunk ${i}\n`;
}
}
export async function GET(request: Request) {
const readableStream = Readable.from(generateData());
return new Response(readableStream, {
headers: { 'Content-Type': 'text/plain; charset=utf-8' },
});
}
شرح الكود:
- دالة
generateData
هي مولد غير متزامن (asynchronous generator) ينتج أجزاء من البيانات مع تأخير. - تنشئ طريقة
Readable.from()
تيارًا قابلاً للقراءة (readable stream) من المولد. - يتم إنشاء كائن
Response
مع التيار القابل للقراءة كنص للاستجابة، ويتم تعيين ترويسةContent-Type
إلىtext/plain
.
المصادقة والترخيص
يعد تأمين نقاط نهاية API الخاصة بك أمرًا بالغ الأهمية. يمكنك تنفيذ المصادقة والترخيص باستخدام الوسيط (middleware) أو مباشرة داخل معالجات التوجيه الخاصة بك.
المصادقة (Authentication)
المصادقة تتحقق من هوية المستخدم الذي يقوم بالطلب. تشمل طرق المصادقة الشائعة ما يلي:
- رموز JWT (JSON Web Tokens): قم بإنشاء رمز عند تسجيل الدخول بنجاح وتحقق منه في الطلبات اللاحقة.
- المصادقة المستندة إلى الجلسة: استخدم ملفات تعريف الارتباط (cookies) لتخزين معرفات الجلسة والتحقق منها في كل طلب.
- OAuth: قم بتفويض المصادقة إلى مزود طرف ثالث مثل Google أو Facebook.
إليك مثال على مصادقة JWT باستخدام الوسيط:
// app/middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import jwt from 'jsonwebtoken';
const secret = process.env.JWT_SECRET || 'your-secret-key'; // Replace with a strong, randomly generated secret
export function middleware(request: NextRequest) {
const token = request.cookies.get('auth-token')?.value;
if (!token) {
return NextResponse.json({ message: 'Authentication required' }, { status: 401 });
}
try {
jwt.verify(token, secret);
return NextResponse.next();
} catch (error) {
return NextResponse.json({ message: 'Invalid token' }, { status: 401 });
}
}
export const config = {
matcher: ['/api/protected/:path*'],
};
الترخيص (Authorization)
يحدد الترخيص الموارد المسموح للمستخدم بالوصول إليها. يعتمد هذا عادةً على الأدوار أو الأذونات.
يمكنك تنفيذ الترخيص داخل معالجات التوجيه الخاصة بك عن طريق التحقق من أدوار المستخدم أو أذوناته وإرجاع خطأ إذا لم يكن لديهم حق الوصول.
// app/api/admin/route.ts
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
// Assume you have a function to get the user's role from the token or session
const userRole = await getUserRole(request);
if (userRole !== 'admin') {
return NextResponse.json({ message: 'Unauthorized' }, { status: 403 });
}
// Logic to retrieve admin data
const adminData = { message: 'Admin data' };
return NextResponse.json(adminData);
}
async function getUserRole(request: Request): Promise {
// Replace with your actual logic to extract the user's role from the request
// This could involve verifying a JWT token or checking a session
return 'admin'; // Example: hardcoded role for demonstration
}
نشر معالجات التوجيه
يتم نشر معالجات التوجيه كدوال بلا خادم (serverless functions) على مزود الاستضافة الذي تختاره. يدعم Next.js منصات نشر مختلفة، بما في ذلك Vercel و Netlify و AWS وغيرها.
بالنسبة لـ Vercel، يكون النشر بسيطًا مثل توصيل مستودع Git الخاص بك بـ Vercel ودفع الكود الخاص بك. يكتشف Vercel تلقائيًا مشروع Next.js الخاص بك وينشر معالجات التوجيه الخاصة بك كدوال بلا خادم.
تقنيات متقدمة
دوال الحافة (Edge Functions)
يمكن نشر معالجات التوجيه كدوال حافة (Edge Functions)، والتي يتم تنفيذها على حافة شبكة توصيل المحتوى (CDN)، أقرب إلى المستخدمين. هذا يمكن أن يقلل بشكل كبير من زمن الوصول ويحسن الأداء.
لنشر معالج توجيه كدالة حافة، أضف وقت تشغيل edge
إلى ملف route.ts
الخاص بك:
export const runtime = 'edge';
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
return NextResponse.json({ message: 'Hello from the Edge!' });
}
إجراءات الخادم (Server Actions)
تسمح لك إجراءات الخادم بتنفيذ كود من جانب الخادم مباشرة من مكونات React الخاصة بك. تعمل معالجات التوجيه وإجراءات الخادم معًا بسلاسة، مما يتيح لك بناء تطبيقات معقدة بسهولة.
إليك مثال على استخدام إجراء خادم لاستدعاء معالج توجيه:
// app/components/MyComponent.tsx
'use client';
import { useState } from 'react';
import { useRouter } from 'next/navigation';
async function handleSubmit(data: FormData) {
'use server';
const name = data.get('name');
const email = data.get('email');
const response = await fetch('/api/users', {
method: 'POST',
body: JSON.stringify({ name, email }),
});
if (response.ok) {
router.refresh(); // Refresh the page to reflect the changes
}
}
export default function MyComponent() {
const router = useRouter();
return (
);
}
التخزين المؤقت (Caching)
يمكن أن يحسن التخزين المؤقت أداء نقاط نهاية API بشكل كبير. يمكنك استخدام ترويسة Cache-Control
للتحكم في كيفية تخزين استجاباتك مؤقتًا بواسطة المتصفحات وشبكات توصيل المحتوى.
return NextResponse.json({ message: 'Success!' }, { status: 200, headers: { 'Cache-Control': 'public, max-age=3600' } });
يعين هذا المثال ترويسة Cache-Control
إلى public, max-age=3600
، مما يخبر المتصفحات وشبكات توصيل المحتوى بتخزين الاستجابة مؤقتًا لمدة ساعة واحدة.
أفضل الممارسات
- استخدم TypeScript: استفد من أمان الأنواع في TypeScript لتحسين جودة الكود ومنع الأخطاء.
- التحقق من صحة الطلبات: تحقق من صحة الطلبات الواردة لضمان سلامة البيانات ومنع الإدخال الضار.
- معالجة الأخطاء بأناقة: قم بتنفيذ معالجة أخطاء مناسبة لتقديم رسائل خطأ مفيدة للعملاء.
- تأمين نقاط النهاية الخاصة بك: قم بتنفيذ المصادقة والترخيص لحماية نقاط نهاية API الخاصة بك.
- استخدم الوسيط (Middleware): استخدم الوسيط للاهتمامات الشاملة مثل المصادقة والتسجيل والتحقق من صحة الطلبات.
- تخزين الاستجابات مؤقتًا: استخدم التخزين المؤقت لتحسين أداء نقاط نهاية API الخاصة بك.
- مراقبة واجهات برمجة التطبيقات الخاصة بك: راقب واجهات برمجة التطبيقات الخاصة بك لتحديد المشكلات وحلها بسرعة.
- توثيق واجهات برمجة التطبيقات الخاصة بك: قم بتوثيق واجهات برمجة التطبيقات الخاصة بك لجعلها سهلة الاستخدام للمطورين الآخرين. ضع في اعتبارك استخدام أدوات مثل Swagger/OpenAPI لتوثيق API.
أمثلة من الواقع العملي
إليك بعض الأمثلة الواقعية لكيفية استخدام معالجات التوجيه:
- واجهة برمجة تطبيقات للتجارة الإلكترونية: إنشاء نقاط نهاية API لإدارة المنتجات والطلبات والمستخدمين.
- واجهة برمجة تطبيقات لوسائل التواصل الاجتماعي: إنشاء نقاط نهاية API لنشر التغريدات ومتابعة المستخدمين واسترداد الجداول الزمنية.
- واجهة برمجة تطبيقات لنظام إدارة المحتوى (CMS): إنشاء نقاط نهاية API لإدارة المحتوى والمستخدمين والإعدادات.
- واجهة برمجة تطبيقات لتحليلات البيانات: إنشاء نقاط نهاية API لجمع البيانات وتحليلها. على سبيل المثال، يمكن لمعالج التوجيه استقبال البيانات من بكسلات التتبع على مواقع الويب المختلفة وتجميع المعلومات لإعداد التقارير.
مثال على التجارة الإلكترونية الدولية: معالج توجيه يستخدم لاسترداد أسعار المنتجات بناءً على بلد المستخدم. يمكن لنقطة النهاية استخدام الموقع الجغرافي للطلب (المشتق من عنوان IP) لتحديد موقع المستخدم وإرجاع الأسعار بالعملة المناسبة. هذا يساهم في تجربة تسوق محلية.
مثال على المصادقة العالمية: معالج توجيه يطبق المصادقة متعددة العوامل (MFA) للمستخدمين في جميع أنحاء العالم. قد يتضمن ذلك إرسال رموز SMS أو استخدام تطبيقات المصادقة، مع احترام لوائح الخصوصية والبنى التحتية للاتصالات في المناطق المختلفة.
توصيل المحتوى متعدد اللغات: معالج توجيه يقدم المحتوى باللغة المفضلة للمستخدم. يمكن تحديد ذلك من ترويسة `Accept-Language` في الطلب. يسلط هذا المثال الضوء على الحاجة إلى ترميز UTF-8 الصحيح ودعم اللغات من اليمين إلى اليسار عند الاقتضاء.
الخاتمة
توفر معالجات التوجيه في Next.js طريقة قوية ومرنة لإنشاء نقاط نهاية API مباشرة داخل تطبيق Next.js الخاص بك. من خلال الاستفادة من معالجات التوجيه، يمكنك بناء واجهات برمجة تطبيقات قوية بسهولة، وتجميع منطق الواجهة الخلفية مع مكونات React الخاصة بك، والاستفادة من ميزات مثل الوسيط (middleware)، والبث (streaming)، ودوال الحافة (Edge Functions).
لقد غطى هذا الدليل الشامل كل شيء بدءًا من الإعداد الأساسي إلى التقنيات المتقدمة. باتباع أفضل الممارسات الموضحة في هذا الدليل، يمكنك بناء واجهات برمجة تطبيقات عالية الجودة تكون آمنة وعالية الأداء وقابلة للصيانة.