
Chào các "dev-er" Gen Z, hôm nay chúng ta sẽ "mổ xẻ" một "thủ thuật" quan trọng trong thế giới API: app.put(). Nghe tên có vẻ "nặng đô" nhưng thực ra nó là "người bạn" cực kỳ hữu ích khi bạn muốn "refresh" dữ liệu trên server một cách "chất như nước cất".
1. app.put() là gì mà "hot" thế?
Để dễ hình dung, anh Creyt thường ví von thế này: Hãy tưởng tượng bạn có một chiếc tủ lạnh (server) và trong đó có một hộp sữa chua (resource) với nhãn "Sữa chua dâu, HSD: hôm qua". Bạn muốn "cập nhật" nó. Có hai cách:
POST(Thêm mới): Bạn mua một hộp sữa chua dâu mới toanh, HSD: tuần sau, rồi đặt thêm vào tủ. Giờ bạn có 2 hộp.PUT(Thay thế hoàn toàn): Bạn vứt hộp sữa chua cũ "hết đát" đi, rồi đặt hộp sữa chua mới toanh, HSD: tuần sau, vào đúng vị trí của hộp cũ. Giờ bạn vẫn chỉ có 1 hộp, nhưng nội dung đã "lột xác" hoàn toàn.PATCH(Sửa một phần): Bạn chỉ muốn dán lại cái nhãn "Sữa chua dâu" thành "Sữa chua việt quất" mà không thay đổi gì về HSD hay các thông tin khác của hộp sữa chua cũ. (Cái này sẽ nói sau, nhưng để các em hình dung sự khác biệt).
Đó, app.put() trong Node.js (thường là với framework Express.js) chính là "thao tác thay thế hoàn toàn" đó. Nó được dùng để cập nhật toàn bộ một tài nguyên (resource) đã tồn tại trên server. Khi bạn gửi một yêu cầu PUT đến một URL nhất định (ví dụ: /api/products/123), bạn đang nói với server rằng: "Này, cái sản phẩm số 123 này, hãy lấy toàn bộ dữ liệu tớ vừa gửi và thay thế hoàn toàn cái cũ bằng cái mới này đi!".
Điểm "ăn tiền" của PUT: Nó có tính Idempotent. Nghĩa là, bạn có gửi 1 lần hay 100 lần yêu cầu PUT y hệt nhau thì kết quả trên server vẫn chỉ là một lần cập nhật duy nhất. Không sợ dữ liệu bị "nhân bản" hay "lỗi logic" nếu đường truyền có vấn đề và client gửi lại yêu cầu nhiều lần.
2. "Show hàng" Code Ví Dụ thực tế
Để các em dễ hình dung, anh Creyt sẽ "code dạo" một ví dụ đơn giản với Express.js. Chúng ta sẽ có một danh sách "việc cần làm" (todos) và dùng app.put() để cập nhật một "việc" cụ thể.
const express = require('express');
const app = express();
const PORT = 3000;
// Middleware để parse JSON body từ request
app.use(express.json());
// Dữ liệu "tưởng tượng" của chúng ta
let todos = [
{ id: 1, title: 'Học Node.js cùng anh Creyt', completed: false },
{ id: 2, title: 'Làm bài tập API', completed: false },
{ id: 3, title: 'Đi ngủ sớm', completed: true }
];
// GET tất cả todos (chỉ để xem dữ liệu)
app.get('/api/todos', (req, res) => {
res.json(todos);
});
// Route app.put() để cập nhật một todo cụ thể
// URL sẽ có dạng: /api/todos/:id (ví dụ: /api/todos/1)
app.put('/api/todos/:id', (req, res) => {
const todoId = parseInt(req.params.id); // Lấy ID từ URL
const updatedTodo = req.body; // Lấy dữ liệu mới từ body của request
// Tìm index của todo cần cập nhật
const todoIndex = todos.findIndex(todo => todo.id === todoId);
// Nếu không tìm thấy todo
if (todoIndex === -1) {
// Trả về 404 Not Found nếu không có tài nguyên này
return res.status(404).json({ message: 'Todo không tìm thấy, "bay màu" rồi em ơi!' });
}
// Kiểm tra dữ liệu gửi lên có hợp lệ không (ví dụ: phải có title)
if (!updatedTodo || !updatedTodo.title) {
return res.status(400).json({ message: 'Dữ liệu không hợp lệ. "Title" là bắt buộc đó!' });
}
// Cập nhật todo bằng cách thay thế hoàn toàn object cũ
// Đảm bảo ID không bị thay đổi, hoặc nếu muốn thay đổi thì phải có logic riêng
// Ở đây, ta giữ nguyên ID nhưng thay thế các trường khác
todos[todoIndex] = { ...updatedTodo, id: todoId };
// Trả về todo đã cập nhật và status 200 OK
res.status(200).json(todos[todoIndex]);
});
// Khởi động server
app.listen(PORT, () => {
console.log(`Server "phiêu" trên cổng ${PORT}. Mở http://localhost:${PORT}/api/todos để xem nhé!`);
});
Cách "test" API này:
- Lưu đoạn code trên vào file
server.js. - Mở Terminal, chạy
npm init -yrồinpm install express. - Chạy
node server.js. - Dùng Postman, Insomnia, hoặc
curlđể gửi request:- GET
http://localhost:3000/api/todosđể xem danh sách ban đầu. - PUT
http://localhost:3000/api/todos/1với Body là JSON:
Sau đó GET lại{ "title": "Học Node.js cùng anh Creyt (Đã hoàn thành!)", "completed": true }/api/todosđể thấy sự thay đổi.
- GET

3. Mẹo "hack não" và Best Practices từ anh Creyt
- "Idempotent" là "thần chú": Luôn nhớ
PUTlà Idempotent. Điều này cực kỳ quan trọng cho sự ổn định của hệ thống, đặc biệt khi mạng "chập chờn" hoặc client cần retry request. Nếu bạn gửi một yêu cầuPUTgiống nhau 10 lần, kết quả trên server vẫn chỉ là một lần cập nhật duy nhất. - "Thay thế hoàn toàn" chứ không phải "sửa một chút": Khi dùng
PUT, hãy xác định rằng bạn muốn thay thế toàn bộ tài nguyên. Nếu bạn chỉ muốn thay đổi một vài trường nhỏ, hãy nghĩ đếnPATCH(để gửi ít dữ liệu hơn và rõ ràng hơn về mục đích). - Validate "đầu vào": Đừng bao giờ tin tưởng dữ liệu từ client. Luôn luôn kiểm tra (validate) dữ liệu
req.bodytrước khi cập nhật vào database. Nếu không, "bug" sẽ "nhảy múa" khắp nơi đó! - Status Codes "chuẩn không cần chỉnh": Trả về
200 OK(kèm theo tài nguyên đã cập nhật) hoặc204 No Content(nếu không cần trả về dữ liệu) cho các requestPUTthành công. Nếu tài nguyên không tồn tại, trả về404 Not Found. Nếu dữ liệu gửi lên "tào lao", trả về400 Bad Request. - Ủa rồi
PUTcó tạo mới được không?: Về lý thuyết,PUTcó thể dùng để tạo mới tài nguyên nếu client chỉ định được ID của tài nguyên đó và tài nguyên đó chưa tồn tại (gọi là "upsert"). Tuy nhiên, trong thực tế API, người ta thường dùngPOSTđể tạo mới (vì server thường tự sinh ID), vàPUTđể cập nhật. Hãy tuân thủ convention này cho dễ hiểu nhé.
4. "Ứng dụng thực chiến" ở đâu?
app.put() được dùng "nhan nhản" trong các hệ thống "xịn sò" mà bạn hay dùng:
- Cập nhật thông tin cá nhân (Profile Update): Khi bạn thay đổi toàn bộ thông tin trong phần "Edit Profile" trên Facebook, Instagram, LinkedIn... (tên, email, ngày sinh, giới tính...). Một request
PUTsẽ gửi toàn bộ object người dùng mới lên để thay thế cái cũ. - Chỉnh sửa sản phẩm trong E-commerce: Admin "sửa" thông tin một sản phẩm (tên, mô tả, giá, hình ảnh...). Thay vì sửa từng trường, họ có thể gửi toàn bộ object sản phẩm mới qua
PUT. - Quản lý cấu hình (Configuration Management): Thay thế toàn bộ file cấu hình của một dịch vụ nào đó trên server.
5. Anh Creyt đã từng "thử nghiệm" và "khuyên dùng" cho case nào?
"Hồi xưa anh Creyt mới vào nghề, cứ cái gì update là quất POST hết. Đến khi hệ thống lớn lên, dữ liệu loạn cào cào vì không kiểm soát được trạng thái, rồi client gửi lại request trùng lặp là tạo ra dữ liệu 'rác'. Rồi mới nhận ra PUT nó có cái hay của nó, đặc biệt là tính Idempotent, giúp hệ thống mình 'dễ đoán' hơn nhiều."
Anh Creyt khuyên dùng PUT khi:
- Bạn muốn thay thế toàn bộ trạng thái của một tài nguyên. Ví dụ: bạn có một tài liệu Word, bạn không muốn sửa từng câu mà muốn thay thế toàn bộ nội dung bằng một phiên bản mới hơn.
- Client đã có đủ thông tin về tài nguyên và muốn "ghi đè" lên nó. Thường là các form chỉnh sửa có đầy đủ các trường thông tin của đối tượng.
- Khi bạn cần đảm bảo tính Idempotent để tránh các vấn đề phát sinh do lỗi mạng hoặc client gửi lại yêu cầu nhiều lần.
Khi nào nên dùng PATCH?
- Khi bạn chỉ muốn cập nhật một hoặc một vài trường nhỏ của tài nguyên, không phải toàn bộ. Ví dụ: chỉ cập nhật trạng thái
completedcủa mộttodotừfalsesangtruemà không thay đổititle. DùngPATCHsẽ hiệu quả hơn về băng thông và rõ ràng hơn về ý định.
Nhớ nhé các em, chọn đúng HTTP method không chỉ là "đúng sách vở" mà còn là "nghệ thuật" giúp API của bạn "trong sáng", dễ bảo trì và "bá đạo" hơn rất nhiều đó! "Cố lên" và "chiến" thôi!
Thuộc Series: Nodejs
Bài giảng này được tự động xuất bản ngẫu nhiên từ thư viện kiến thức. Đừng quên đón xem các Từ khoá Hướng Dẫn tiếp theo nhé!