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 missingYê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 };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.
- Trong
routes/tasks.js, thêmPUT /api/tasks/:id. Phần thân phải chứa cả hai trường, ví dụ{ "title": "Book the big room", "done": true }. - Thay
titlevàdonecủa tác vụ bằng các giá trị trong phần thân. Giữ lạiidvàcreatedAttừ 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" } - Nếu phần thân thiếu
titlehoặcdone, 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": falselà một giá trị hợp lệ. - 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;
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
1Tài nguyên và động từ
Tài nguyên và URLTạo tài nguyên bằng POST4Trình duyệt, phiên bản và cấu hình
Origin là gìCho phép một origin khácCORSTrang gọi APITự luyện tập: Playground Express