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.
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.
- Trong
routes/tasks.js, ở tuyến POST, hãy kiểm tratitle:- 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
errorcó chứa từtitle, ví dụ:{ "error": "title must be a string of 1 to 100 characters" } - 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àtruehoặcfalse. 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:
Một yêu cầu PATCH bị từ chối sẽ không làm thay đổi gì.{ "error": "done must be true or false" } - Nếu phần thân gửi
- 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;
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 API2Xác thực và lỗi
Xác thực đầu vàoTự luyện tập: Playground Express