Versionamento
Fa parte della sezione API REST del percorso Node.js di Coddy. Lezione 22 di 25.
Modificare la struttura di una risposta compromette tutti i client che la utilizzano già. Una versione nel percorso consente ai client vecchi e nuovi di coesistere: /api/v1/orders oggi, /api/v2/orders quando la struttura cambia. Quando un percorso viene spostato, quello vecchio risponde con un reindirizzamento a quello nuovo:
GET /api/orders/5 → 308 Location: /api/v1/orders/5
POST /api/orders → 308 Location: /api/v1/orders301 e 302 consentono ai client di ripetere una richiesta POST come GET, eliminando il corpo. 308 indica «ripeti lì la stessa richiesta», inclusi metodo e corpo. All'interno di un middleware montato, req.url non contiene più il percorso di montaggio, mentre req.originalUrl lo conserva per intero:
// in app.use('/api/orders', ...) per GET /api/orders/5?full=1
req.url // '/5?full=1'
req.originalUrl // '/api/orders/5?full=1'Sfida
FacileLa tua API cambierà in modi che i vecchi client non si aspetteranno, quindi inserisci un numero di versione nei suoi percorsi. L’API di oggi diventa la versione 1, all’indirizzo /api/v1/tasks, e i vecchi indirizzi reindirizzano i client lì.
- In
server.js, monta il router delle attività su/api/v1/tasksinvece che su/api/tasks. - Sempre in
server.js, aggiungi un middleware montato su/api/tasksche esegua solo il reindirizzamento. Risponde con lo stato 308 all’indirizzo corrispondente sotto/api/v1, mantenendo il resto del percorso e la stringa di query. All’interno di un middleware montato,req.originalUrlcontiene l’indirizzo completo precedente. Per esempio:GET /api/tasks/2reindirizza a/api/v1/tasks/2.POST /api/tasksreindirizza a/api/v1/tasks.GET /api/tasks?done=false&sort=titlereindirizza a/api/v1/tasks?done=false&sort=title.
Usa 308, non 301: dopo un 308, un client ripete una POST come POST, corpo incluso.
- In
routes/tasks.js, la route POST impostaLocationsul nuovo indirizzo, per esempio/api/v1/tasks/4per l’attività 4.
Prova: GET /api/tasks/2 restituisce 308 e la scheda Headers mostra Location: /api/v1/tasks/2. La barra della richiesta mostra il reindirizzamento stesso; non lo segue. Invia una POST con { "title": "Order new chairs" } a /api/tasks: ottieni 308 con Location: /api/v1/tasks e non viene creata alcuna attività. Invia lo stesso corpo con una POST a /api/v1/tasks: 201 con Location: /api/v1/tasks/4. GET /api/v1/tasks/2 restituisce l’attività 2.
Provalo tu
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();
// Consente alle pagine su BOARD_ORIGIN di chiamare questa API dal browser.
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);
// Gli errori provenienti dalle route arrivano qui. Un corpo che non è JSON valido è un errore del
// client (400); qualsiasi altro errore è nostro (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');
});
Tutte le lezioni di API REST
1Risorse e verbi
Risorse e URLCreare con POST4Browser, versioni e configurazione
Che cos'è un'origineConsentire un'altra origineCORSUna pagina che chiama l'APIEsercitati da solo: Playground Express