Menu
CoddyTech

ניהול גרסאות

חלק מהיחידה 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'
challenge icon

אתגר

קל

ה-API שלך ישתנה בדרכים שלקוחות ישנים לא יצפו להן, לכן יש לכלול מספר גרסה בנתיבים שלו. ה-API של היום הופך לגרסה 1, בכתובת /api/v1/tasks, והכתובות הישנות מפנות את הלקוחות אליה.

  1. ב-server.js, יש לחבר את הנתב של המשימות בכתובת /api/v1/tasks במקום /api/tasks.
  2. גם ב-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, כולל גוף הבקשה.

  3. ב-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 אונליין