Menu
CoddyTech

אימות קלט

חלק מהיחידה REST APIs במסלול ה-Node.js של Coddy. שיעור 6 מתוך 25.

לקוח יכול לשלוח כל דבר בגוף הבקשה, ו-if (!name) עוצר רק ערכים ריקים. 123, true ו-["x"] הם ערכי אמת ועוברים. גם מחרוזת של רווחים עוברת: תפסו אותה באמצעות trim(), כי ' '.trim() הוא ''. בדקו את הטיפוס של כל שדה באמצעות typeof, ולאחר מכן בדקו את המגבלות שלו:

const { seats } = req.body ?? {};
if (typeof seats !== 'number' || !Number.isInteger(seats) || seats < 1) {
    return res.status(400).json({ error: 'seats must be a whole number from 1' });
}

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

challenge icon

אתגר

קל

כרגע if (!title) מאפשר לעבור כותרת כמו 123 או " ". בדקו את הסוג ואת האורך של כל שדה לפני ששומרים אותו.

  1. בנתיב POST שבקובץ routes/tasks.js, בדקו את title:
    • הוא חייב להיות מחרוזת.
    • הוא לא יכול להיות ריק או להכיל רווחים בלבד.
    • אורכו יכול להיות עד 100 תווים, כולל רווחים.

    אם אחד מהתנאים האלה אינו מתקיים, החזירו תגובת סטטוס 400 עם משפט שגיאה שמכיל את המילה error, למשל:

    { "error": "title must be a string of 1 to 100 characters" }
  2. בנתיב PATCH, בדקו רק את השדות שהגוף שולח:
    • אם הוא שולח title, חלים אותו כלל ואותו סוג של שגיאה.
    • אם הוא שולח done, הערך חייב להיות true או false. אחרת, החזירו תגובת סטטוס 400 עם שגיאה שמכילה את המילה done:
    { "error": "done must be true or false" }
    PATCH שנדחה לא משנה דבר.
  3. גופים תקינים ממשיכים לעבוד: POST עדיין מחזיר 201, ו-PATCH עם { "done": true } עדיין מחזיר 200. השאירו את PUT כפי שהוא; גם Schemas בודק אותו באמצעות zod.

נסו זאת: שלחו POST עם { "title": 123 } אל /api/tasks: תקבלו 400 עם שגיאת הכותרת. שלחו POST עם { "title": " " }: גם כאן תקבלו 400. שלחו PATCH /api/tasks/2 עם { "done": "yes" }: תקבלו 400 עם שגיאת done, ו-GET /api/tasks/2 עדיין יציג "done": false. שלחו PATCH /api/tasks/2 עם { "done": true }: תקבלו 200.

נסו בעצמכם

import { Router } from 'express';
import { nextId, tasks } from '../store.js';

const router = Router();

router.get('/', (req, res) => {
    res.json(tasks);
});

router.get('/:id', (req, res) => {
    const task = tasks.find((t) => t.id === Number(req.params.id));
    if (!task) {
        return res.status(404).json({ error: 'Task not found' });
    }
    res.json(task);
});

router.post('/', (req, res) => {
    const { title } = req.body ?? {};
    if (!title) {
        return res.status(400).json({ error: 'title is required' });
    }
    const task = { id: nextId(), title, done: false, createdAt: new Date().toISOString() };
    tasks.push(task);
    res.status(201).location(`/api/tasks/${task.id}`).json(task);
});

router.patch('/:id', (req, res) => {
    const task = tasks.find((t) => t.id === Number(req.params.id));
    if (!task) {
        return res.status(404).json({ error: 'Task not found' });
    }
    const { title, done } = req.body ?? {};
    if (title !== undefined) task.title = title;
    if (done !== undefined) task.done = done;
    res.json(task);
});

router.put('/:id', (req, res) => {
    const index = tasks.findIndex((t) => t.id === Number(req.params.id));
    if (index === -1) {
        return res.status(404).json({ error: 'Task not found' });
    }
    const { title, done } = req.body ?? {};
    if (title === undefined || done === undefined) {
        return res.status(400).json({ error: 'PUT needs every field: title and done' });
    }
    const { id, createdAt } = tasks[index];
    tasks[index] = { id, title, done, createdAt };
    res.json(tasks[index]);
});

router.delete('/:id', (req, res) => {
    const index = tasks.findIndex((t) => t.id === Number(req.params.id));
    if (index === -1) {
        return res.status(404).json({ error: 'Task not found' });
    }
    tasks.splice(index, 1);
    res.status(204).end();
});

export default router;
quiz iconבחנו את עצמכם

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

כל השיעורים ביחידה REST APIs

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