Menu
CoddyTech

Xác thực đầu vào

Thuộc phần REST API trong hành trình Node.js của Coddy. Bài học 6 trên 25.

Máy khách có thể gửi bất cứ thứ gì trong phần thân yêu cầu, còn if (!name) chỉ chặn các giá trị rỗng. 123, true và ["x"] là các giá trị truthy nên vẫn lọt qua. Một chuỗi chỉ chứa dấu cách cũng lọt qua: hãy kiểm tra bằng trim(), vì ' '.trim() cho kết quả là ''. Kiểm tra kiểu dữ liệu của từng trường bằng typeof, rồi kiểm tra các giới hạn:

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' });
}

Viết thông báo dành cho người đọc phản hồi: nêu tên trường và cho biết trường đó cần có giá trị như thế nào để họ biết cần sửa gì. Một yêu cầu PATCH chỉ kiểm tra các trường được gửi kèm, vì những trường còn lại không thay đổi.

challenge icon

Thử thách

Dễ

Hiện tại, if (!title) vẫn cho qua tiêu đề như 123 hoặc " ". Hãy kiểm tra kiểu dữ liệu và kích thước của từng trường trước khi lưu.

  1. Trong routes/tasks.js, ở tuyến POST, hãy kiểm tra title:
    • Nó phải là chuỗi.
    • Nó không được để trống hoặc chỉ chứa dấu cách.
    • Nó dài tối đa 100 ký tự, tính cả dấu cách.

    Nếu không đáp ứng bất kỳ điều kiện nào trong số này, hãy phản hồi với mã trạng thái 400 và một câu error có chứa từ title, ví dụ:

    { "error": "title must be a string of 1 to 100 characters" }
  2. Trong tuyến PATCH, chỉ kiểm tra các trường mà phần thân yêu cầu gửi:
    • Nếu phần thân gửi title, hãy áp dụng quy tắc tương tự và kiểu thông báo lỗi tương tự.
    • Nếu phần thân gửi done, giá trị phải là true hoặc false. Nếu không, hãy phản hồi với mã trạng thái 400 và lỗi có chứa từ done:
    { "error": "done must be true or false" }
    Một yêu cầu PATCH bị từ chối sẽ không làm thay đổi gì.
  3. Các phần thân hợp lệ vẫn hoạt động: POST vẫn trả về 201 và PATCH với { "done": true } vẫn trả về 200. Giữ nguyên PUT; Schemas cũng kiểm tra bằng zod.

Thử nhé: Gửi POST { "title": 123 } đến /api/tasks: bạn nhận được 400 cùng lỗi về title. Gửi POST { "title": " " }: cũng nhận được 400. Gửi PATCH /api/tasks/2 với { "done": "yes" }: nhận được 400 cùng lỗi về done, còn GET /api/tasks/2 vẫn hiển thị "done": false. Gửi PATCH /api/tasks/2 với { "done": true }: nhận được 200.

Tự làm thử

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 iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong REST API

Tự luyện tập: Playground Express