Menu
CoddyTech

קריאת גוף הבקשה

חלק מהיחידה יסודות 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 ולא לשמור דבר.

challenge icon

אתגר

קל

מבקרים יכולים להוסיף מתכונים משלהם. תוכנית שולחת את המתכון החדש כ-JSON בגוף של בקשת POST, וה-API שלך שומר אותו.

  1. ב-server.js, הוסף את express.json() לצד שורות ה-app.use האחרות, לפני הנתיבים, כדי שגוף JSON יגיע אל req.body.
  2. הוסף נתיב לבקשות POST אל /api/recipes. הוא קורא את title ואת tags מתוך הגוף, לדוגמה {"title": "Miso Soup", "tags": ["vegan", "soup"]}.
  3. הוא יוצר את המתכון החדש עם המזהה המספרי הבא: לארבעת המתכונים יש מזהים מ-1 עד 4, לכן המתכון החדש הראשון יקבל את המספר 5. הוא שומר את הכותרת ואת התגיות שנשלחו. אם לא נשלחו tags, השתמש ברשימה ריקה, [].
  4. הוא מוסיף את המתכון למערך recipes, כך ש-GET /api/recipes יציג אותו. לאחר מכן הוא משיב עם סטטוס 201 ועם המתכון החדש כ-JSON: {"id": 5, "title": "Miso Soup", "tags": ["vegan", "soup"]}
  5. אם אין בגוף 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');
});
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה יסודות Express

תרגלו בעצמכם: Express אונליין