בקשות ותשובות לעומק
כל Route ב-Express מקבל שני אובייקטים: req (מה שהלקוח שלח) ו-res (מה שנחזיר לו). בשיעורים הקודמים השתמשנו בהם בקטנה. כאן נעבור על כל מה שבאמת צריך כדי לבנות API.
ארבעה מקורות למידע בבקשה
| מקור | דוגמה בכתובת/בבקשה | איך קוראים |
|---|---|---|
| פרמטר בנתיב | /users/42 | req.params.id |
| Query String | /search?q=ספר&page=2 | req.query.q |
| גוף הבקשה | JSON שנשלח ב-POST | req.body |
| Headers | Authorization: Bearer ... | req.get('Authorization') |
פרמטרים בנתיב
app.get('/users/:userId/posts/:postId', (req, res) => {
const { userId, postId } = req.params;
// כל הפרמטרים מגיעים כמחרוזות
res.json({ userId: Number(userId), postId: Number(postId) });
});
פרמטר אופציונלי ב-Express 5 נכתב בסוגריים מסולסלים: '/files{/:name}'.
Query String
// GET /products?category=books&page=2
app.get('/products', (req, res) => {
const category = req.query.category ?? 'all';
const page = Math.max(1, Number(req.query.page) || 1);
res.json({ category, page });
});
אל תסמכו על מה שמגיע ב-Query: הוא יכול להיות חסר, ריק או מחרוזת במקום מספר. תמיד ברירת מחדל והמרה.
גוף הבקשה
Express לא קורא את הגוף לבד. צריך Middleware שיודע לפענח אותו, פעם אחת בראש האפליקציה:
app.use(express.json()); // JSON (API)
app.use(express.urlencoded({ extended: false })); // טפסי HTML רגילים
app.post('/api/contact', (req, res) => {
const { name, email } = req.body;
if (!name || !email) {
return res.status(400).json({ error: 'שם ואימייל הם שדות חובה' });
}
res.status(201).json({ received: { name, email } });
});
שכחתם את express.json()? req.body יהיה undefined. זו הטעות הכי נפוצה בשיעור הזה.
Headers ומידע נוסף על הבקשה
app.get('/whoami', (req, res) => {
res.json({
method: req.method, // 'GET'
path: req.path, // '/whoami'
userAgent: req.get('User-Agent'),
ip: req.ip,
wantsJson: req.accepts('json'),
});
});
סוגי תשובות
res.send('טקסט או HTML'); // Content-Type לפי התוכן
res.json({ ok: true }); // JSON
res.status(201).json(newItem); // קוד סטטוס + JSON
res.sendStatus(204); // רק קוד סטטוס, בלי גוף
res.redirect('/login'); // הפניה (302)
res.redirect(301, '/new-address'); // הפניה קבועה
res.sendFile(path.join(import.meta.dirname, 'report.pdf'));
res.download('./files/invoice.pdf'); // מוריד כקובץ
כלל ברזל: תשובה אחת לכל בקשה
// ❌ באג: אם אין שם, נשלחות שתי תשובות
app.post('/api/users', (req, res) => {
if (!req.body.name) {
res.status(400).json({ error: 'חסר שם' });
}
res.status(201).json({ ok: true });
});
// ✅ return עוצר את הפונקציה אחרי התשובה הראשונה
app.post('/api/users', (req, res) => {
if (!req.body.name) {
return res.status(400).json({ error: 'חסר שם' });
}
res.status(201).json({ ok: true });
});
הגרסה הראשונה זורקת Cannot set headers after they are sent to the client. כשרואים את השגיאה הזו, מחפשים תשובה שנשלחת פעמיים.
Headers ו-Cookies בתשובה
res.set('Cache-Control', 'no-store');
res.cookie('theme', 'dark', { maxAge: 1000 * 60 * 60 * 24 * 30, httpOnly: true, sameSite: 'lax' });
res.clearCookie('theme');
דוגמה מלאה להרצה
בקובץ req-res.js יש נתיב לכל אחד מהנושאים כאן. הריצו אותו ונסו בדפדפן את /search?q=test, /headers ו-/status/404.
בדקו את עצמכם
נסו לענות לבד לפני שאתם פותחים את התשובה.
-
איפה נמצא הערך מהכתובת
/search?q=ספר?הצגת התשובה
תשובה ד. params לחלקי הנתיב, query ל-Query String, body לגוף הבקשה.
-
מה גורם לשגיאה "Cannot set headers after they are sent"?
הצגת התשובה
תשובה ג. כותבים return לפני כל res.json מוקדם.
-
איזה קוד סטטוס מתאים אחרי יצירה מוצלחת?
הצגת התשובה
תשובה א. 201 Created, ובדרך כלל מחזירים גם את המשאב החדש.