למדו כיצד ליצור נקודות קצה חזקות ל-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 שלכם, האחראית על עיבוד בקשות, אינטראקציה עם מסדי נתונים והחזרת תגובות.
היתרונות בשימוש במטפלי נתיבים
- מיקום משותף (Colocation): מטפלי נתיבים יושבים ישירות לצד רכיבי ה-React שלכם בתוך ספריית ה-
app
, מה שמקדם ארגון ותחזוקת קוד טובים יותר. - תמיכה ב-TypeScript: תמיכה מובנית ב-TypeScript מבטיחה בטיחות טיפוסים (type safety) וחוויית מפתחים משופרת.
- שילוב Middleware: שלבו בקלות middleware למשימות כמו אימות, הרשאות ואימות בקשות.
- תמיכה בהזרמה (Streaming): מטפלי נתיבים יכולים להזרים נתונים, מה שמאפשר לכם לשלוח תגובות באופן הדרגתי, דבר המועיל עבור מערכי נתונים גדולים או תהליכים ארוכים.
- פונקציות קצה (Edge Functions): פרסו מטפלי נתיבים כפונקציות קצה לתגובות עם זמן שיהוי נמוך, קרוב יותר למשתמשים שלכם, תוך מינוף רשתות CDN גלובליות.
- עיצוב API פשוט: מטפלי נתיבים מספקים API נקי ואינטואיטיבי לטיפול בבקשות ותגובות.
- שילוב עם Server Actions: אינטגרציה הדוקה עם 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: 'שלום מ-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: 'שלום מ-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) {
// לוגיקה לשליפת כל המשתמשים ממסד הנתונים
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
}
הסבר:
- הפונקציה
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)
כדי לגשת לפרמטרים של שאילתה, ניתן להשתמש בבנאי (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/
};
הסבר:
- הפונקציה
middleware
בודקת אם קיים טוקן אימות בקובצי ה-cookie של הבקשה. - אם הטוקן חסר, היא מפנה את המשתמש לדף ההתחברות.
- אחרת, היא מאפשרת לבקשה להמשיך למטפל הנתיבים.
- האובייקט
config
מציין שה-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 });
}
}
הסבר:
- הבלוק
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)); // הדמיית השהיה
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
היא מחולל (generator) אסינכרוני שמניב נתחי נתונים עם השהיה. - המתודה
Readable.from()
יוצרת זרם קריא (readable stream) מהמחולל. - אובייקט ה-
Response
נוצר עם הזרם הקריא כגוף, והכותרתContent-Type
מוגדרת ל-text/plain
.
אימות והרשאות
אבטחת נקודות הקצה של ה-API שלכם היא חיונית. ניתן ליישם אימות והרשאות באמצעות middleware או ישירות בתוך מטפלי הנתיבים שלכם.
אימות (Authentication)
אימות מוודא את זהותו של המשתמש המבצע את הבקשה. שיטות אימות נפוצות כוללות:
- JWT (JSON Web Tokens): יצירת טוקן בעת התחברות מוצלחת ואימותו בבקשות עוקבות.
- אימות מבוסס סשן (Session-based Authentication): שימוש בקובצי cookie לאחסון מזהי סשן ואימותם בכל בקשה.
- OAuth: האצלת האימות לספק צד שלישי כמו גוגל או פייסבוק.
הנה דוגמה לאימות 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 לשמור את התגובה במטמון למשך שעה אחת.
שיטות עבודה מומלצות
- השתמשו ב-TypeScript: נצלו את בטיחות הטיפוסים של TypeScript כדי לשפר את איכות הקוד ולמנוע שגיאות.
- אמתו בקשות: אמתו בקשות נכנסות כדי להבטיח את שלמות הנתונים ולמנוע קלט זדוני.
- טפלו בשגיאות בחן: ישמו טיפול נכון בשגיאות כדי לספק הודעות שגיאה אינפורמטיביות ללקוחות.
- אבטחו את נקודות הקצה שלכם: ישמו אימות והרשאות כדי להגן על נקודות הקצה של ה-API שלכם.
- השתמשו ב-Middleware: השתמשו ב-middleware לדאגות רוחב כמו אימות, רישום ואימות בקשות.
- שמרו תגובות במטמון: השתמשו במטמון כדי לשפר את ביצועי נקודות הקצה של ה-API שלכם.
- נטרו את ממשקי ה-API שלכם: נטרו את ממשקי ה-API שלכם כדי לזהות ולפתור בעיות במהירות.
- תעדו את ממשקי ה-API שלכם: תעדו את ממשקי ה-API שלכם כדי להקל על השימוש בהם על ידי מפתחים אחרים. שקלו להשתמש בכלים כמו Swagger/OpenAPI לתיעוד API.
דוגמאות מהעולם האמיתי
הנה כמה דוגמאות מהעולם האמיתי לאופן שבו ניתן להשתמש במטפלי נתיבים:
- API למסחר אלקטרוני: יצירת נקודות קצה של API לניהול מוצרים, הזמנות ומשתמשים.
- API לרשת חברתית: יצירת נקודות קצה של API לפרסום ציוצים, מעקב אחר משתמשים ושליפת צירי זמן.
- API למערכת ניהול תוכן (CMS): יצירת נקודות קצה של API לניהול תוכן, משתמשים והגדרות.
- API לניתוח נתונים: יצירת נקודות קצה של API לאיסוף וניתוח נתונים. לדוגמה, מטפל נתיבים יכול לקבל נתונים מפיקסלי מעקב באתרים שונים ולאגד את המידע לדיווח.
דוגמה למסחר אלקטרוני בינלאומי: מטפל נתיבים המשמש לשליפת תמחור מוצרים על בסיס מדינת המשתמש. נקודת הקצה יכולה להשתמש במיקום הגיאוגרפי של הבקשה (הנגזר מכתובת ה-IP) כדי לקבוע את מיקום המשתמש ולהחזיר מחירים במטבע המתאים. זה תורם לחוויית קנייה מותאמת אישית.
דוגמה לאימות גלובלי: מטפל נתיבים המיישם אימות רב-גורמי (MFA) עבור משתמשים ברחבי העולם. זה יכול לכלול שליחת קודי SMS או שימוש באפליקציות אימות, תוך כיבוד תקנות הפרטיות ותשתיות התקשורת של אזורים שונים.
אספקת תוכן רב-לשוני: מטפל נתיבים המספק תוכן בשפה המועדפת על המשתמש. ניתן לקבוע זאת מכותרת Accept-Language
בבקשה. דוגמה זו מדגישה את הצורך בקידוד UTF-8 נכון ובתמיכה בשפות מימין לשמאל במידת הצורך.
סיכום
מטפלי הנתיבים של Next.js מספקים דרך חזקה וגמישה ליצור נקודות קצה של API ישירות בתוך יישום ה-Next.js שלכם. על ידי מינוף מטפלי נתיבים, תוכלו לבנות ממשקי API חזקים בקלות, למקם את לוגיקת צד השרת שלכם יחד עם רכיבי ה-React שלכם, ולהפיק תועלת מתכונות כמו middleware, הזרמה ופונקציות קצה.
מדריך מקיף זה כיסה הכל, מהגדרה בסיסית ועד טכניקות מתקדמות. על ידי ביצוע שיטות העבודה המומלצות המתוארות במדריך זה, תוכלו לבנות ממשקי API איכותיים שהם מאובטחים, ביצועיים וניתנים לתחזוקה.