Quản lý phiên bản
Thuộc phần REST API trong hành trình Node.js của Coddy. Bài học 22 trên 25.
Thay đổi hình dạng của câu trả lời sẽ làm hỏng mọi ứng dụng khách đang sử dụng nó. Thêm phiên bản vào đường dẫn giúp các ứng dụng khách cũ và mới hoạt động song song: /api/v1/orders hiện tại, /api/v2/orders khi hình dạng thay đổi. Khi đường dẫn thay đổi, đường dẫn cũ sẽ chuyển hướng đến đường dẫn mới:
GET /api/orders/5 → 308 Location: /api/v1/orders/5
POST /api/orders → 308 Location: /api/v1/orders301 và 302 cho phép ứng dụng khách gửi lại yêu cầu POST dưới dạng GET, làm mất phần thân yêu cầu. 308 có nghĩa là “gửi lại cùng yêu cầu đến đó”, bao gồm cả phương thức và phần thân. Bên trong middleware được gắn vào ứng dụng, req.url không còn phần đường dẫn gắn middleware, còn req.originalUrl giữ lại toàn bộ đường dẫn:
// trong app.use('/api/orders', ...) với GET /api/orders/5?full=1
req.url // '/5?full=1'
req.originalUrl // '/api/orders/5?full=1'Thử thách
DễAPI của bạn sẽ thay đổi theo những cách mà các client cũ không mong đợi, vì vậy hãy thêm số phiên bản vào các đường dẫn. API hiện tại trở thành phiên bản 1 tại /api/v1/tasks, còn các địa chỉ cũ sẽ chuyển client đến đó.
- Trong
server.js, gắn bộ định tuyến tasks tại/api/v1/tasksthay vì/api/tasks. - Cũng trong
server.js, thêm middleware gắn tại/api/taskschỉ làm nhiệm vụ chuyển hướng. Middleware trả về trạng thái 308 đến cùng địa chỉ dưới/api/v1, giữ nguyên phần còn lại của đường dẫn và chuỗi truy vấn. Bên trong middleware đã gắn,req.originalUrlchứa toàn bộ địa chỉ cũ. Ví dụ:GET /api/tasks/2chuyển hướng đến/api/v1/tasks/2.POST /api/taskschuyển hướng đến/api/v1/tasks.GET /api/tasks?done=false&sort=titlechuyển hướng đến/api/v1/tasks?done=false&sort=title.
Dùng 308, không dùng 301: sau phản hồi 308, client gửi lại yêu cầu POST dưới dạng POST, bao gồm cả phần thân.
- Trong
routes/tasks.js, tuyến POST đặtLocationthành địa chỉ mới, ví dụ/api/v1/tasks/4cho nhiệm vụ 4.
Thử ngay: GET /api/tasks/2 trả về 308, và thẻ Headers hiển thị Location: /api/v1/tasks/2. Thanh yêu cầu hiển thị chính phản hồi chuyển hướng, chứ không tự đi theo chuyển hướng đó. Gửi POST { "title": "Order new chairs" } đến /api/tasks: bạn nhận được 308 với Location: /api/v1/tasks, và không có nhiệm vụ nào được tạo. Gửi POST cùng phần thân đó đến /api/v1/tasks: nhận 201 với Location: /api/v1/tasks/4. GET /api/v1/tasks/2 trả về nhiệm vụ 2.
Tự làm thử
import express from 'express';
import { sendError } from './errors.js';
import taskRoutes from './routes/tasks.js';
const BOARD_ORIGIN = 'https://board.example.com';
const app = express();
// Cho phép các trang trên BOARD_ORIGIN gọi API này từ trình duyệt.
app.use((req, res, next) => {
res.set('Access-Control-Allow-Origin', BOARD_ORIGIN);
if (req.method === 'OPTIONS') {
res.set('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE, OPTIONS');
res.set('Access-Control-Allow-Headers', 'Content-Type');
return res.status(204).end();
}
next();
});
app.use(express.json());
app.use(express.static('public'));
app.use('/api/tasks', taskRoutes);
// Lỗi từ các tuyến được xử lý tại đây. Phần thân không phải JSON hợp lệ là
// lỗi của máy khách (400); các lỗi còn lại thuộc về chúng ta (500).
app.use((err, req, res, next) => {
if (err.type === 'entity.parse.failed') {
return sendError(res, 400, 'invalid_json', 'The body is not valid JSON');
}
console.error(err);
sendError(res, 500, 'server_error', 'Something went wrong');
});
app.listen(3000, () => {
console.log('Task tracker API on port 3000');
});
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