Menu
CoddyTech

Thay thế bằng PUT

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

Một biểu mẫu chỉnh sửa gửi lại toàn bộ tác vụ cùng lúc, gồm mọi trường. PUT có nghĩa là “thay thế tài nguyên bằng nội dung này”, vì vậy phần thân yêu cầu phải đầy đủ.

PATCH /api/invoices/7  { "paid": true }               → paid changes
PUT   /api/invoices/7  { "amount": 90, "paid": true } → invoice 7 replaced
PUT   /api/invoices/7  { "paid": true }               → 400: amount missing

Yêu cầu PUT thiếu một trường sẽ trả về 400: thay thế bằng một phần hóa đơn sẽ làm mất số tiền. Các trường do máy chủ quản lý, như id và thời điểm tạo, lấy từ phiên bản cũ, không bao giờ lấy từ phần thân yêu cầu:

const { id, issuedAt } = invoices[index];
invoices[index] = { id, amount, paid, issuedAt };
challenge icon

Thử thách

Dễ

Một biểu mẫu chỉnh sửa gửi toàn bộ tác vụ cùng lúc. Thêm một tuyến PUT để thay thế tác vụ bằng dữ liệu mà máy khách gửi.

  1. Trong routes/tasks.js, thêm PUT /api/tasks/:id. Phần thân phải chứa cả hai trường, ví dụ { "title": "Book the big room", "done": true }.
  2. Thay title và done của tác vụ bằng các giá trị trong phần thân. Giữ lại id và createdAt từ tác vụ đã lưu, không bao giờ lấy chúng từ phần thân. Phản hồi với trạng thái 200 và toàn bộ tác vụ:
    { "id": 2, "title": "Book the big room", "done": true, "createdAt": "2026-03-03T10:30:00.000Z" }
  3. Nếu phần thân thiếu title hoặc done, phản hồi với trạng thái 400 và { "error": "PUT needs every field: title and done" }, đồng thời không thay đổi gì. Một trường chỉ bị thiếu khi hoàn toàn không có trong phần thân: "done": false là một giá trị hợp lệ.
  4. Nếu không có tác vụ nào mang id đó, phản hồi với trạng thái 404 và { "error": "Task not found" }, giống các tuyến khác.

Thử ngay: PUT /api/tasks/2 với { "title": "Book the big room", "done": true } trả về 200 cùng tác vụ ở trên. Sau đó, PUT /api/tasks/2 chỉ với { "done": true } trả về 400, và GET /api/tasks/2 vẫn hiển thị "Book the big room". PUT /api/tasks/99 với cả hai trường trả về 404.

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.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