فارسی

یاد بگیرید چگونه با استفاده از Route Handler های Next.js نقاط پایانی API قدرتمند ایجاد کنید. این راهنما همه چیز را از راه‌اندازی اولیه تا تکنیک‌های پیشرفته، با مثال‌های کاربردی و بهترین شیوه‌ها پوشش می‌دهد.

Next.js Route Handlers: راهنمای جامع برای ایجاد نقاط پایانی API

Next.js با ویژگی‌های قدرتمند خود مانند رندر سمت سرور، تولید سایت استاتیک و اکنون، Route Handlers، شیوه ساخت برنامه‌های وب را متحول کرده است. Route Handlers روشی انعطاف‌پذیر و کارآمد برای ایجاد نقاط پایانی (endpoints) API مستقیماً در داخل برنامه Next.js شما فراهم می‌کنند. این راهنما به بررسی مفهوم Route Handlers، مزایای آن‌ها و نحوه استفاده مؤثر از آن‌ها برای ساخت APIهای قوی می‌پردازد.

Route Handler های Next.js چه هستند؟

Route Handlers توابعی هستند که در دایرکتوری app یک پروژه Next.js تعریف می‌شوند و درخواست‌های HTTP ورودی را مدیریت می‌کنند. برخلاف رویکرد قدیمی pages/api (که از API Routes استفاده می‌کند)، Route Handlers روشی ساده‌تر و انعطاف‌پذیرتر برای تعریف نقاط پایانی API در کنار کامپوننت‌های React شما ارائه می‌دهند. آن‌ها اساساً توابع بدون سرور (serverless) هستند که بر روی edge یا محیط سرور انتخابی شما اجرا می‌شوند.

Route Handlers را به عنوان منطق بک‌اند برنامه Next.js خود در نظر بگیرید که مسئول پردازش درخواست‌ها، تعامل با پایگاه‌های داده و بازگرداندن پاسخ‌ها هستند.

مزایای استفاده از Route Handlers

راه‌اندازی پروژه Next.js شما

قبل از پرداختن به Route Handlers، اطمینان حاصل کنید که یک پروژه Next.js با دایرکتوری app راه‌اندازی کرده‌اید. اگر در حال شروع یک پروژه جدید هستید، از دستور زیر استفاده کنید:

npx create-next-app@latest my-nextjs-app

در طول فرآیند راه‌اندازی، دایرکتوری app را انتخاب کنید تا سیستم مسیریابی جدید فعال شود.

ایجاد اولین Route Handler

بیایید یک نقطه پایانی API ساده ایجاد کنیم که یک پاسخ JSON برمی‌گرداند. یک دایرکتوری جدید در داخل دایرکتوری app ایجاد کنید، به عنوان مثال، /app/api/hello. در داخل این دایرکتوری، فایلی به نام route.ts (یا route.js اگر از TypeScript استفاده نمی‌کنید) ایجاد کنید.

در اینجا کد اولین Route Handler شما آمده است:

// app/api/hello/route.ts
import { NextResponse } from 'next/server';

export async function GET(request: Request) {
 return NextResponse.json({ message: 'سلام از طرف Route Handlers های Next.js!' });
}

توضیح:

اکنون، می‌توانید با مراجعه به /api/hello در مرورگر خود یا استفاده از ابزاری مانند curl یا Postman به این نقطه پایانی دسترسی پیدا کنید.

مدیریت متدهای مختلف HTTP

Route Handlers از متدهای مختلف 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) {
 // منطقی برای بازیابی همه کاربران از پایگاه داده
 const users = [{ id: 1, name: 'John Doe' }, { id: 2, name: 'Jane Smith' }]; // داده‌های نمونه
 return NextResponse.json(users);
}

export async function POST(request: Request) {
 const data = await request.json(); // بدنه درخواست را به عنوان JSON تجزیه می‌کند
 // منطقی برای ایجاد یک کاربر جدید در پایگاه داده با استفاده از 'data'
 const newUser = { id: 3, name: data.name, email: data.email }; // نمونه
 return NextResponse.json(newUser, { status: 201 }); // کاربر جدید را با کد وضعیت 201 Created برمی‌گرداند
}

توضیح:

دسترسی به داده‌های درخواست

آبجکت request دسترسی به اطلاعات مختلف در مورد درخواست ورودی، از جمله هدرها، پارامترهای کوئری و بدنه درخواست را فراهم می‌کند.

هدرها (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 });

پاسخ‌های متنی (Text Responses)

از سازنده 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 در NextResponse.json() یا new Response() تنظیم کنید:

return NextResponse.json({ message: 'Success!' }, { status: 200, headers: { 'Cache-Control': 'no-cache' } });

ادغام با Middleware

Middleware به شما امکان می‌دهد کدی را قبل از اینکه درخواست توسط Route Handler شما مدیریت شود، اجرا کنید. این برای احراز هویت، اعطای دسترسی، لاگ‌گیری و سایر نگرانی‌های متقاطع (cross-cutting concerns) مفید است.

برای ایجاد یک middleware، فایلی به نام middleware.ts (یا middleware.js) در دایرکتوری app یا هر زیرشاخه‌ای ایجاد کنید. این middleware بر روی تمام مسیرهای داخل آن دایرکتوری و زیرشاخه‌های آن اعمال خواهد شد.

// 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*'], // این middleware را به مسیرهایی که با /protected/ شروع می‌شوند اعمال کن
};

توضیح:

مدیریت خطا (Error Handling)

مدیریت صحیح خطا برای ساخت APIهای قوی بسیار مهم است. شما می‌توانید از بلوک‌های try...catch برای مدیریت استثناها و بازگرداندن پاسخ‌های خطای مناسب استفاده کنید.

export async function GET(request: Request) {
 try {
 // شبیه‌سازی یک خطا
 throw new Error('Something went wrong!');
 } catch (error: any) {
 console.error('Error:', error);
 return NextResponse.json({ error: error.message }, { status: 500 });
 }
}

توضیح:

پاسخ‌های جریانی (Streaming Responses)

Route Handlers از پاسخ‌های جریانی پشتیبانی می‌کنند، که به شما امکان می‌دهد داده‌ها را به صورت تدریجی به کلاینت ارسال کنید. این به ویژه برای مجموعه داده‌های بزرگ یا فرآیندهای طولانی‌مدت مفید است.

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)); // شبیه‌سازی تأخیر
 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' },
 });
}

توضیح:

احراز هویت و اعطای دسترسی (Authentication and Authorization)

امن کردن نقاط پایانی API شما بسیار حیاتی است. شما می‌توانید احراز هویت و اعطای دسترسی را با استفاده از middleware یا مستقیماً در داخل Route Handlers خود پیاده‌سازی کنید.

احراز هویت (Authentication)

احراز هویت، هویت کاربری که درخواست را ارسال می‌کند، تأیید می‌کند. روش‌های رایج احراز هویت عبارتند از:

در اینجا یک مثال از احراز هویت JWT با استفاده از middleware آورده شده است:

// 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'; // با یک کلید مخفی قوی و تصادفی جایگزین کنید

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)

اعطای دسترسی تعیین می‌کند که یک کاربر به چه منابعی اجازه دسترسی دارد. این معمولاً بر اساس نقش‌ها یا مجوزها است.

شما می‌توانید اعطای دسترسی را در داخل Route Handlers خود با بررسی نقش‌ها یا مجوزهای کاربر و بازگرداندن یک خطا در صورت عدم دسترسی، پیاده‌سازی کنید.

// app/api/admin/route.ts
import { NextResponse } from 'next/server';

export async function GET(request: Request) {
 // فرض کنید تابعی برای گرفتن نقش کاربر از توکن یا نشست دارید
 const userRole = await getUserRole(request);

 if (userRole !== 'admin') {
 return NextResponse.json({ message: 'Unauthorized' }, { status: 403 });
 }

 // منطقی برای بازیابی داده‌های ادمین
 const adminData = { message: 'Admin data' };
 return NextResponse.json(adminData);
}

async function getUserRole(request: Request): Promise {
 // با منطق واقعی خود برای استخراج نقش کاربر از درخواست جایگزین کنید
 // این می‌تواند شامل تأیید یک توکن JWT یا بررسی یک نشست باشد
 return 'admin'; // مثال: نقش هاردکد شده برای نمایش
}

استقرار (Deploying) Route Handlers

Route Handlers به عنوان توابع بدون سرور (serverless) بر روی ارائه‌دهنده هاستینگ انتخابی شما مستقر می‌شوند. Next.js از پلتفرم‌های مختلف استقرار، از جمله Vercel، Netlify، AWS و غیره پشتیبانی می‌کند.

برای Vercel، استقرار به سادگی اتصال مخزن Git شما به Vercel و push کردن کد شماست. Vercel به طور خودکار پروژه Next.js شما را شناسایی کرده و Route Handlers شما را به عنوان توابع بدون سرور مستقر می‌کند.

تکنیک‌های پیشرفته

توابع Edge (Edge Functions)

Route Handlers می‌توانند به عنوان توابع Edge مستقر شوند که در لبه یک CDN، نزدیک‌تر به کاربران شما اجرا می‌شوند. این می‌تواند به طور قابل توجهی تأخیر را کاهش داده و عملکرد را بهبود بخشد.

برای استقرار یک Route Handler به عنوان یک تابع Edge، ران‌تایم edge را به فایل route.ts خود اضافه کنید:

export const runtime = 'edge';

import { NextResponse } from 'next/server';

export async function GET(request: Request) {
 return NextResponse.json({ message: 'سلام از Edge!' });
}

اکشن‌های سرور (Server Actions)

Server Actions به شما امکان می‌دهند کد سمت سرور را مستقیماً از کامپوننت‌های React خود اجرا کنید. Route Handlers و Server Actions به طور یکپارچه با هم کار می‌کنند و به شما امکان می‌دهند برنامه‌های پیچیده را به راحتی بسازید.

در اینجا مثالی از استفاده از یک Server Action برای فراخوانی یک Route Handler آورده شده است:

// 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(); // صفحه را برای اعمال تغییرات رفرش کن
 }
}

export default function MyComponent() {
 const router = useRouter();

 return (
 




); }

کش کردن (Caching)

کش کردن می‌تواند به طور قابل توجهی عملکرد نقاط پایانی API شما را بهبود بخشد. شما می‌توانید از هدر Cache-Control برای کنترل نحوه کش شدن پاسخ‌های خود توسط مرورگرها و CDNها استفاده کنید.

return NextResponse.json({ message: 'Success!' }, { status: 200, headers: { 'Cache-Control': 'public, max-age=3600' } });

این مثال هدر Cache-Control را روی public, max-age=3600 تنظیم می‌کند، که به مرورگرها و CDNها می‌گوید که پاسخ را برای یک ساعت کش کنند.

بهترین شیوه‌ها (Best Practices)

مثال‌های دنیای واقعی

در اینجا چند مثال واقعی از نحوه استفاده از Route Handlers آورده شده است:

مثال تجارت الکترونیک بین‌المللی: یک Route Handler که برای بازیابی قیمت‌گذاری محصول بر اساس کشور کاربر استفاده می‌شود. این نقطه پایانی می‌تواند از موقعیت جغرافیایی درخواست (که از آدرس IP استخراج می‌شود) برای تعیین موقعیت کاربر و بازگرداندن قیمت‌ها با واحد پول مناسب استفاده کند. این به یک تجربه خرید بومی‌سازی شده کمک می‌کند.

مثال احراز هویت جهانی: یک Route Handler که احراز هویت چند عاملی (MFA) را برای کاربران در سراسر جهان پیاده‌سازی می‌کند. این می‌تواند شامل ارسال کدهای SMS یا استفاده از برنامه‌های احراز هویت باشد، در حالی که به مقررات حریم خصوصی و زیرساخت‌های مخابراتی مناطق مختلف احترام می‌گذارد.

تحویل محتوای چند زبانه: یک Route Handler که محتوا را به زبان ترجیحی کاربر تحویل می‌دهد. این را می‌توان از هدر `Accept-Language` در درخواست تعیین کرد. این مثال نیاز به رمزگذاری مناسب UTF-8 و پشتیبانی از زبان‌های راست به چپ در صورت لزوم را برجسته می‌کند.

نتیجه‌گیری

Route Handlers های Next.js یک راه قدرتمند و انعطاف‌پذیر برای ایجاد نقاط پایانی API مستقیماً در داخل برنامه Next.js شما فراهم می‌کنند. با بهره‌گیری از Route Handlers، می‌توانید APIهای قوی را به راحتی بسازید، منطق بک‌اند خود را با کامپوننت‌های React خود هم‌مکان کنید و از ویژگی‌هایی مانند middleware، streaming و توابع Edge بهره‌مند شوید.

این راهنمای جامع همه چیز را از راه‌اندازی اولیه تا تکنیک‌های پیشرفته پوشش داده است. با پیروی از بهترین شیوه‌های ذکر شده در این راهنما، می‌توانید APIهای با کیفیتی بسازید که امن، کارآمد و قابل نگهداری باشند.