עברית

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

נתיבי API של Next.js: בניית ה-Backend שלכם בקלות

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

מהם נתיבי API של Next.js?

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

חשבו עליהם כעל פונקציות backend קלות משקל, הפועלות לפי דרישה ומשולבות באופן חלק עם ה-front-end של Next.js שלכם.

היתרונות בשימוש בנתיבי API של Next.js

צעדים ראשונים עם נתיבי API של Next.js

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

npx create-next-app my-app
cd my-app

כעת, צרו קובץ בשם hello.js בתוך ספריית /pages/api:

// pages/api/hello.js
export default function handler(req, res) {
  res.status(200).json({ name: 'John Doe' })
}

קוד זה מגדיר נתיב API פשוט המגיב עם אובייקט JSON המכיל את השם "John Doe". כדי לגשת לנתיב API זה, הריצו את שרת הפיתוח של Next.js:

npm run dev

לאחר מכן, פתחו את הדפדפן ונווטו אל http://localhost:3000/api/hello. אתם אמורים לראות את תגובת ה-JSON הבאה:

{"name": "John Doe"}

הבנת ה-Handler של נתיב ה-API

פונקציית ה-handler בנתיב ה-API שלכם מקבלת שני ארגומנטים:

אתם יכולים להשתמש באובייקטים אלה כדי לטפל בסוגים שונים של בקשות, לקרוא נתונים מגוף הבקשה, להגדיר כותרות תגובה ולשלוח סוגים שונים של תגובות.

טיפול במתודות HTTP שונות

אתם יכולים להשתמש במאפיין req.method כדי לקבוע את מתודת ה-HTTP של הבקשה הנכנסת ולטפל במתודות שונות בהתאם. לדוגמה:

// pages/api/method.js
export default function handler(req, res) {
  if (req.method === 'GET') {
    // Handle GET request
    res.status(200).json({ message: 'This is a GET request' })
  } else if (req.method === 'POST') {
    // Handle POST request
    res.status(200).json({ message: 'This is a POST request' })
  } else {
    // Handle other methods
    res.status(405).json({ message: 'Method Not Allowed' })
  }
}

בדוגמה זו, נתיב ה-API מטפל בבקשות GET ו-POST. אם מתודת הבקשה היא GET, הוא מגיב עם אובייקט JSON המכיל את ההודעה "This is a GET request". אם מתודת הבקשה היא POST, הוא מגיב עם אובייקט JSON המכיל את ההודעה "This is a POST request". אם מתודת הבקשה היא כל דבר אחר, הוא מגיב עם שגיאת 405 Method Not Allowed.

קריאת נתונים מגוף הבקשה (Request Body)

עבור בקשות POST, PUT ו-PATCH, לעתים קרובות תצטרכו לקרוא נתונים מגוף הבקשה. Next.js מספקת תמיכה מובנית בפענוח (parsing) גופי בקשה מסוג JSON ו-URL-encoded. כדי לפענח גוף בקשת JSON, אתם יכולים להשתמש במאפיין req.body. לדוגמה:

// pages/api/post.js
export default async function handler(req, res) {
  if (req.method === 'POST') {
    const { name, email } = req.body

    // Process the data
    console.log('Name:', name)
    console.log('Email:', email)

    res.status(200).json({ message: 'Data received successfully' })
  } else {
    res.status(405).json({ message: 'Method Not Allowed' })
  }
}

כדי לבדוק נתיב API זה, אתם יכולים להשתמש בכלי כמו Postman או curl כדי לשלוח בקשת POST עם גוף JSON:

curl -X POST -H "Content-Type: application/json" -d '{"name": "Jane Doe", "email": "jane.doe@example.com"}' http://localhost:3000/api/post

הגדרת כותרות תגובה (Response Headers)

אתם יכולים להשתמש במתודה res.setHeader() כדי להגדיר כותרות תגובה. זה שימושי להגדרת סוג התוכן, בקרת מטמון (cache) ומידע חשוב אחר. לדוגמה:

// pages/api/headers.js
export default function handler(req, res) {
  res.setHeader('Content-Type', 'application/json')
  res.setHeader('Cache-Control', 's-maxage=3600')
  res.status(200).json({ message: 'Hello, world!' })
}

בדוגמה זו, נתיב ה-API מגדיר את כותרת ה-Content-Type ל-application/json, מה שמציין שהתגובה היא אובייקט JSON. הוא גם מגדיר את כותרת ה-Cache-Control ל-s-maxage=3600, מה שאומר לדפדפן ול-CDN לשמור את התגובה במטמון למשך עד שעה אחת.

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

חשוב לטפל בשגיאות בחן בנתיבי ה-API שלכם. אתם יכולים להשתמש בבלוקי try-catch כדי לתפוס חריגות (exceptions) ולשלוח תגובות שגיאה מתאימות ללקוח. לדוגמה:

// pages/api/error.js
export default async function handler(req, res) {
  try {
    // Simulate an error
    throw new Error('Something went wrong')
  } catch (error) {
    console.error(error)
    res.status(500).json({ message: 'Internal Server Error' })
  }
}

בדוגמה זו, נתיב ה-API מדמה שגיאה על ידי זריקת אובייקט Error חדש. בלוק ה-catch תופס את השגיאה, רושם אותה לקונסולה, ושולח תגובת 500 Internal Server Error ללקוח. שקלו להשתמש במערכת רישום (logging) חזקה כמו Sentry או Datadog לסביבות ייצור.

התחברות למסד נתונים

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

הנה דוגמה לאופן החיבור למסד נתונים של MongoDB בנתיב API של Next.js:

// pages/api/mongodb.js
import { MongoClient } from 'mongodb'

const uri = process.env.MONGODB_URI
const options = {}

let client
let clientPromise

if (!process.env.MONGODB_URI) {
  throw new Error('Please add your Mongo URI to .env.local')
}

if (process.env.NODE_ENV === 'development') {
  // In development mode, use a global variable so that the value
  // is preserved across module reloads caused by HMR (Hot Module Replacement).
  if (!global._mongoClientPromise) {
    client = new MongoClient(uri, options)
    global._mongoClientPromise = client.connect()
  }
  clientPromise = global._mongoClientPromise
} else {
  // In production mode, it's best to not use a global variable.
  client = new MongoClient(uri, options)
  clientPromise = client.connect()
}

// Export a module-scoped MongoClient promise. By doing this in a
// separate module, the client can be safely reused across multiple
// functions.  See: https://github.com/vercel/next.js/blob/canary/examples/with-mongodb/lib/mongodb.js
export default async function handler(req, res) {
  try {
    const client = await clientPromise
    const db = client.db(process.env.MONGODB_DB)
    const collection = db.collection('users')

    const users = await collection.find({}).toArray()

    res.status(200).json({ users })
  } catch (e) {
    console.error(e)
    res.status(500).json({ message: 'Failed to fetch users' })
  }
}

לפני הרצת קוד זה, ודאו שהתקנתם את חבילת mongodb:

npm install mongodb

אתם צריכים גם להגדיר את משתני הסביבה MONGODB_URI ו-MONGODB_DB. משתנים אלה צריכים להיות מוגדרים בקובץ .env.local שלכם (או בהגדרות משתני הסביבה של ספק האירוח שלכם לסביבת ייצור). ה-MONGODB_URI מכיל את מחרוזת החיבור למסד הנתונים של MongoDB, ו-MONGODB_DB מציין את שם מסד הנתונים.

אימות והרשאות (Authentication and Authorization)

הגנה על נתיבי ה-API שלכם חיונית לאבטחה. ניתן לאבטח נתיבי API של Next.js באמצעות טכניקות אימות והרשאות שונות, כולל:

הנה דוגמה לאופן הגנה על נתיב API באמצעות אימות JWT:

// pages/api/protected.js
import jwt from 'jsonwebtoken'

const secret = process.env.JWT_SECRET

export default function handler(req, res) {
  const token = req.headers.authorization?.split(' ')[1]

  if (!token) {
    return res.status(401).json({ message: 'Unauthorized' })
  }

  try {
    const decoded = jwt.verify(token, secret)
    // The "decoded" object contains the user information embedded in the token
    // For example: const userId = decoded.userId;

    // Continue processing the request
    res.status(200).json({ message: 'Protected resource accessed successfully' })
  } catch (error) {
    return res.status(401).json({ message: 'Invalid token' })
  }
}

לפני הרצת קוד זה, ודאו שהתקנתם את חבילת jsonwebtoken:

npm install jsonwebtoken

אתם צריכים גם להגדיר את משתנה הסביבה JWT_SECRET. זה צריך להיות מפתח סודי חזק שנוצר באופן אקראי ומשמש לחתימה ואימות של JWTs. אחסנו אותו באופן מאובטח ולעולם אל תחשפו אותו בקוד צד-הלקוח שלכם.

Middleware (תווכה)

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

הנה דוגמה לאופן יצירת middleware פשוט לרישום:

// utils/middleware.js
export function withLogging(handler) {
  return async function(req, res) {
    console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`)
    return handler(req, res)
  }
}

כדי להשתמש ב-middleware זה, פשוט עטפו את ה-handler של נתיב ה-API שלכם בפונקציה withLogging:

// pages/api/logged.js
import { withLogging } from '../../utils/middleware'

async function handler(req, res) {
  res.status(200).json({ message: 'This request was logged' })
}

export default withLogging(handler)

שיטות עבודה מומלצות לבניית נתיבי API של Next.js

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

משימות רקע (Background Jobs)

למשימות ארוכות טווח שאסור להן לחסום את תגובת ה-API, שקלו להשתמש במשימות רקע. אתם יכולים להשתמש בספריות כמו BullMQ או Bree כדי לנהל את משימות הרקע שלכם ולעבד אותן באופן אסינכרוני.

WebSockets

ליישומים בזמן אמת, אתם יכולים להשתמש ב-WebSockets בנתיבי ה-API של Next.js. ספריות כמו Socket.IO ו-ws מקלות על יצירת חיבורים קבועים בין הלקוח לשרת.

GraphQL

אם אתם צריכים דרך גמישה ויעילה יותר לאחזר נתונים, שקלו להשתמש ב-GraphQL. אתם יכולים להשתמש בספריות כמו Apollo Server או Yoga כדי ליצור נקודת קצה של GraphQL API באפליקציית ה-Next.js שלכם.

סיכום

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