עברית

למדו כיצד ליצור נקודות קצה חזקות ל-API באמצעות מטפלי נתיבים (Route Handlers) של Next.js. מדריך זה מכסה הכל, מהגדרה בסיסית ועד טכניקות מתקדמות, עם דוגמאות מעשיות ושיטות עבודה מומלצות.

מטפלי נתיבים (Route Handlers) ב-Next.js: מדריך מקיף ליצירת נקודות קצה של API

Next.js חוללה מהפכה באופן שבו אנו בונים יישומי ווב עם התכונות החזקות שלה כמו רינדור בצד השרת, יצירת אתרים סטטיים, וכעת, מטפלי נתיבים (Route Handlers). מטפלי נתיבים מספקים דרך גמישה ויעילה ליצור נקודות קצה של API ישירות בתוך יישום ה-Next.js שלכם. מדריך זה סוקר את המושג של מטפלי נתיבים, את יתרונותיהם, וכיצד להשתמש בהם ביעילות לבניית ממשקי API חזקים.

מהם מטפלי נתיבים (Route Handlers) ב-Next.js?

מטפלי נתיבים הן פונקציות המוגדרות בתוך ספריית ה-app של פרויקט Next.js המטפלות בבקשות HTTP נכנסות. בניגוד לגישה הישנה של pages/api (המשתמשת ב-API Routes), מטפלי נתיבים מציעים דרך יעילה וגמישה יותר להגדיר נקודות קצה של API לצד רכיבי ה-React שלכם. הן למעשה פונקציות serverless המורצות ב-edge או בסביבת השרת שבחרתם.

חשבו על מטפלי נתיבים כלוגיקה של צד השרת ביישום ה-Next.js שלכם, האחראית על עיבוד בקשות, אינטראקציה עם מסדי נתונים והחזרת תגובות.

היתרונות בשימוש במטפלי נתיבים

הקמת פרויקט 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: 'שלום מ-Next.js Route Handlers!' });
}

הסבר:

כעת, תוכלו לגשת לנקודת קצה זו על ידי ניווט ל-/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) {
 // לוגיקה לשליפת כל המשתמשים ממסד הנתונים
 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), פרמטרים של שאילתה (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)

כדי לגשת לפרמטרים של שאילתה, ניתן להשתמש בבנאי (constructor) של 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(), תלוי בסוג התוכן (content type).

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: 'הצלחה!', data: { name: 'John Doe' } }, { status: 200 });

תגובות טקסט

השתמשו בבנאי new Response() כדי להחזיר תגובות טקסט פשוט:

return new Response('שלום, עולם!', { 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: 'הצלחה!' }, { status: 200, headers: { 'Cache-Control': 'no-cache' } });

שילוב Middleware

Middleware מאפשר לכם להריץ קוד לפני שבקשה מטופלת על ידי מטפל הנתיבים שלכם. זה שימושי לאימות, הרשאות, רישום (logging), ודאגות רוחב אחרות.

כדי ליצור 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/
};

הסבר:

טיפול בשגיאות

טיפול נכון בשגיאות הוא חיוני לבניית ממשקי API חזקים. ניתן להשתמש בבלוקים של try...catch כדי לטפל בחריגות ולהחזיר תגובות שגיאה מתאימות.

export async function GET(request: Request) {
 try {
 // הדמיית שגיאה
 throw new Error('משהו השתבש!');
 } catch (error: any) {
 console.error('שגיאה:', error);
 return NextResponse.json({ error: error.message }, { status: 500 });
 }
}

הסבר:

הזרמת תגובות (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)); // הדמיית השהיה
 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' },
 });
}

הסבר:

אימות והרשאות

אבטחת נקודות הקצה של ה-API שלכם היא חיונית. ניתן ליישם אימות והרשאות באמצעות middleware או ישירות בתוך מטפלי הנתיבים שלכם.

אימות (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: 'נדרש אימות' }, { status: 401 });
 }

 try {
 jwt.verify(token, secret);
 return NextResponse.next();
 } catch (error) {
 return NextResponse.json({ message: 'טוקן לא חוקי' }, { 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) {
 // נניח שיש לכם פונקציה לקבלת תפקיד המשתמש מהטוקן או מהסשן
 const userRole = await getUserRole(request);

 if (userRole !== 'admin') {
 return NextResponse.json({ message: 'לא מורשה' }, { status: 403 });
 }

 // לוגיקה לשליפת נתוני מנהל מערכת
 const adminData = { message: 'נתוני מנהל מערכת' };
 return NextResponse.json(adminData);
}

async function getUserRole(request: Request): Promise {
 // יש להחליף בלוגיקה האמיתית שלכם לחילוץ תפקיד המשתמש מהבקשה
 // זה יכול לכלול אימות טוקן JWT או בדיקת סשן
 return 'admin'; // דוגמה: תפקיד קבוע לצורך הדגמה
}

פריסת מטפלי נתיבים

מטפלי נתיבים נפרסים כפונקציות serverless על ספק האירוח שבחרתם. Next.js תומך בפלטפורמות פריסה שונות, כולל Vercel, Netlify, AWS ועוד.

עבור Vercel, הפריסה פשוטה כמו חיבור מאגר ה-Git שלכם ל-Vercel ודחיפת הקוד שלכם. Vercel מזהה אוטומטית את פרויקט ה-Next.js שלכם ופורס את מטפלי הנתיבים שלכם כפונקציות serverless.

טכניקות מתקדמות

פונקציות קצה (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: 'שלום מהקצה!' });
}

Server Actions

Server Actions מאפשרות לכם להריץ קוד צד-שרת ישירות מרכיבי ה-React שלכם. מטפלי נתיבים ו-Server Actions עובדים יחד בצורה חלקה, ומאפשרים לכם לבנות יישומים מורכבים בקלות.

הנה דוגמה לשימוש ב-Server Action כדי לקרוא למטפל נתיבים:

// 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: 'הצלחה!' }, { status: 200, headers: { 'Cache-Control': 'public, max-age=3600' } });

דוגמה זו מגדירה את כותרת ה-Cache-Control ל-public, max-age=3600, מה שאומר לדפדפנים ולרשתות CDN לשמור את התגובה במטמון למשך שעה אחת.

שיטות עבודה מומלצות

דוגמאות מהעולם האמיתי

הנה כמה דוגמאות מהעולם האמיתי לאופן שבו ניתן להשתמש במטפלי נתיבים:

דוגמה למסחר אלקטרוני בינלאומי: מטפל נתיבים המשמש לשליפת תמחור מוצרים על בסיס מדינת המשתמש. נקודת הקצה יכולה להשתמש במיקום הגיאוגרפי של הבקשה (הנגזר מכתובת ה-IP) כדי לקבוע את מיקום המשתמש ולהחזיר מחירים במטבע המתאים. זה תורם לחוויית קנייה מותאמת אישית.

דוגמה לאימות גלובלי: מטפל נתיבים המיישם אימות רב-גורמי (MFA) עבור משתמשים ברחבי העולם. זה יכול לכלול שליחת קודי SMS או שימוש באפליקציות אימות, תוך כיבוד תקנות הפרטיות ותשתיות התקשורת של אזורים שונים.

אספקת תוכן רב-לשוני: מטפל נתיבים המספק תוכן בשפה המועדפת על המשתמש. ניתן לקבוע זאת מכותרת Accept-Language בבקשה. דוגמה זו מדגישה את הצורך בקידוד UTF-8 נכון ובתמיכה בשפות מימין לשמאל במידת הצורך.

סיכום

מטפלי הנתיבים של Next.js מספקים דרך חזקה וגמישה ליצור נקודות קצה של API ישירות בתוך יישום ה-Next.js שלכם. על ידי מינוף מטפלי נתיבים, תוכלו לבנות ממשקי API חזקים בקלות, למקם את לוגיקת צד השרת שלכם יחד עם רכיבי ה-React שלכם, ולהפיק תועלת מתכונות כמו middleware, הזרמה ופונקציות קצה.

מדריך מקיף זה כיסה הכל, מהגדרה בסיסית ועד טכניקות מתקדמות. על ידי ביצוע שיטות העבודה המומלצות המתוארות במדריך זה, תוכלו לבנות ממשקי API איכותיים שהם מאובטחים, ביצועיים וניתנים לתחזוקה.