קריאת גוף הבקשה
חלק מהיחידה יסודות Express במסלול ה-Node.js של Coddy. שיעור 15 מתוך 23.
בקשת POST שולחת נתונים בגוף הבקשה, ו-Express לא קוראת את הגוף אלא אם מבקשים ממנה.
app.use(express.json());
app.post('/api/loans', (req, res) => {
const { bookId, member } = req.body;
res.status(201).json({ bookId, member, due: '2026-11-08' });
});בקשת GET מבקשת משהו; בקשת POST שולחת משהו כדי ליצור אותו. express.json() היא תוכנת ביניים שקוראת כל גוף JSON לתוך req.body. בלעדיה, הערך של req.body הוא undefined. נתיב שיוצר משהו משיב עם קוד 201 ועם מה שיצר.
בדקו את גוף הבקשה לפני ששומרים אותו. שדה חסר הוא טעות של הלקוח, ולכן יש להשיב עם קוד 400 ולא לשמור דבר.
אתגר
קלמבקרים יכולים להוסיף מתכונים משלהם. תוכנית שולחת את המתכון החדש כ-JSON בגוף של בקשת POST, וה-API שלך שומר אותו.
- ב-
server.js, הוסף אתexpress.json()לצד שורות ה-app.useהאחרות, לפני הנתיבים, כדי שגוף JSON יגיע אלreq.body. - הוסף נתיב לבקשות POST אל
/api/recipes. הוא קורא אתtitleואתtagsמתוך הגוף, לדוגמה{"title": "Miso Soup", "tags": ["vegan", "soup"]}. - הוא יוצר את המתכון החדש עם המזהה המספרי הבא: לארבעת המתכונים יש מזהים מ-1 עד 4, לכן המתכון החדש הראשון יקבל את המספר 5. הוא שומר את הכותרת ואת התגיות שנשלחו. אם לא נשלחו
tags, השתמש ברשימה ריקה,[]. - הוא מוסיף את המתכון למערך
recipes, כך ש-GET /api/recipesיציג אותו. לאחר מכן הוא משיב עם סטטוס 201 ועם המתכון החדש כ-JSON:{"id": 5, "title": "Miso Soup", "tags": ["vegan", "soup"]} - אם אין בגוף
title, הוא לא שומר דבר ומשיב עם סטטוס 400 ועם ה-JSON הזה:{"error": "A recipe needs a title"}
נסה זאת: לחץ על הפעלה. בחר POST בבורר השיטה, הקלד /api/recipes כנתיב והזן {"title": "Miso Soup", "tags": ["vegan", "soup"]} בתיבת הגוף. אתה אמור לראות סטטוס 201 ואת המתכון עם "id": 5. בחר GET ושלח /api/recipes: חמישה מתכונים, כאשר Miso Soup מופיע אחרון. לאחר מכן שלח POST עם {"tags": ["dinner"]} אל /api/recipes: סטטוס 400 ו-{"error":"A recipe needs a title"}. GET /api/recipes עדיין מציג חמישה מתכונים.
נסו בעצמכם
import { escapeHtml } from './html.js';
import express from 'express';
import { randomUUID } from 'node:crypto';
import { recipes } from './data.js';
const app = express();
app.use((req, res, next) => {
console.log(`${req.method} ${req.url}`);
next();
});
app.use((req, res, next) => {
res.set('X-Request-Id', randomUUID());
next();
});
app.use(express.static('public'));
app.get('/', (req, res) => {
const items = recipes.map((r) => `<li><a href="/recipes/${r.id}">${escapeHtml(r.title)}</a></li>`);
res.send(`<link rel="stylesheet" href="/style.css"><h1>Recipe Box</h1><ul>${items.join('')}</ul>`);
});
// type('text') שולח טקסט פשוט, כך שכל כותרת מופיעה בשורה משלה.
app.get('/recipes', (req, res) => {
const { tag } = req.query;
const list = tag ? recipes.filter((recipe) => recipe.tags.includes(tag)) : recipes;
res.type('text').send(list.map((recipe) => recipe.title).join('\n'));
});
app.get('/recipes/:id', (req, res) => {
const recipe = recipes.find((r) => r.id === Number(req.params.id));
if (!recipe) {
res.status(404).send('No such recipe');
return;
}
res.send(recipe.title);
});
app.get('/api/recipes', (req, res) => {
res.json(recipes);
});
app.get('/api/recipes/:id', (req, res) => {
const recipe = recipes.find((r) => r.id === Number(req.params.id));
if (!recipe) {
res.status(404).json({ error: 'No such recipe' });
return;
}
res.json(recipe);
});
app.get('/about', (req, res) => {
res.send('Recipe Box collects family recipes.');
});
app.get('/menu', (req, res) => {
res.redirect(301, '/recipes');
});
app.get('/menu/:id', (req, res) => {
res.redirect(301, `/recipes/${req.params.id}`);
});
app.listen(3000, () => {
console.log('Recipe Box is running on port 3000');
});
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה יסודות Express
תרגלו בעצמכם: Express אונליין