ניהול גרסאות
חלק מהיחידה REST APIs במסלול ה-Node.js של Coddy. שיעור 22 מתוך 25.
שינוי המבנה של תשובה שובר כל לקוח שכבר משתמש בה. ציון גרסה בנתיב מאפשר ללקוחות ישנים וחדשים לפעול זה לצד זה: /api/v1/orders היום, /api/v2/orders כשהמבנה משתנה. כשנתיב משתנה, הנתיב הישן מחזיר הפניה לנתיב החדש:
GET /api/orders/5 → 308 Location: /api/v1/orders/5
POST /api/orders → 308 Location: /api/v1/ordersהקודים 301 ו-302 מאפשרים ללקוחות לחזור על בקשת POST כבקשת GET, וכך גוף הבקשה נעלם. 308 אומר "חזרו על אותה בקשה שם", כולל השיטה וגוף הבקשה. בתוך תוכנת ביניים שמחוברת לנתיב, req.url כבר לא מכיל את נתיב החיבור, בעוד req.originalUrl שומר את כולו:
// בתוך app.use('/api/orders', ...) עבור GET /api/orders/5?full=1
req.url // '/5?full=1'
req.originalUrl // '/api/orders/5?full=1'אתגר
קלה-API שלך ישתנה בדרכים שלקוחות ישנים לא יצפו להן, לכן יש לכלול מספר גרסה בנתיבים שלו. ה-API של היום הופך לגרסה 1, בכתובת /api/v1/tasks, והכתובות הישנות מפנות את הלקוחות אליה.
- ב-
server.js, יש לחבר את הנתב של המשימות בכתובת/api/v1/tasksבמקום/api/tasks. - גם ב-
server.js, יש להוסיף תווכה שמחוברת בכתובת/api/tasksומבצעת הפניה בלבד. היא משיבה עם קוד מצב 308 לכתובת המקבילה תחת/api/v1, תוך שמירה על שאר הנתיב ועל מחרוזת השאילתה. בתוך תווכה מחוברת,req.originalUrlמכיל את הכתובת הישנה המלאה. לדוגמה:GET /api/tasks/2מפנה אל/api/v1/tasks/2.POST /api/tasksמפנה אל/api/v1/tasks.GET /api/tasks?done=false&sort=titleמפנה אל/api/v1/tasks?done=false&sort=title.
יש להשתמש ב-308, ולא ב-301: לאחר הפניית 308, לקוח שולח בקשת POST חוזרת כבקשת POST, כולל גוף הבקשה.
- ב-
routes/tasks.js, נתיב POST מגדיר אתLocationלכתובת החדשה, לדוגמה/api/v1/tasks/4עבור משימה 4.
נסו זאת: GET /api/tasks/2 מחזיר 308, וכרטיסיית הכותרות מציגה Location: /api/v1/tasks/2. סרגל הבקשות מציג את ההפניה עצמה; הוא לא עוקב אחריה. שלחו POST עם { "title": "Order new chairs" } אל /api/tasks: תקבלו 308 עם Location: /api/v1/tasks, ולא תיווצר משימה. שלחו POST עם אותו גוף אל /api/v1/tasks: תקבלו 201 עם Location: /api/v1/tasks/4. GET /api/v1/tasks/2 מחזיר את משימה 2.
נסו בעצמכם
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();
// מאפשר לדפים ב-BOARD_ORIGIN לקרוא ל-API הזה מהדפדפן.
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);
// שגיאות מהנתיבים מגיעות לכאן. גוף שאינו JSON תקין הוא
// באשמת הלקוח (400); כל שגיאה אחרת היא באשמתנו (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');
});
כל השיעורים ביחידה REST APIs
תרגלו בעצמכם: Express אונליין