API Versioning — Cheat Sheet

Tag: api, rest, versioning, backend, architecture, routing

Livello: intermedio

TL;DR: Strategie di versioning per API REST, gestione dei breaking change, retrocompatibilità e ciclo di deprecazione.

Concetti chiave

URI path versioning: esplicito e visibile nell'URL (/api/v1/resource), facile da instradare a livello reverse proxy.

Header versioning: usa custom header (X-API-Version: 1), mantiene URL puliti ma riduce l'intuitività e complica il caching.

Content negotiation (Accept header): specifica la versione via MIME type (application/vnd.company.v1+json), standard REST puro.

Query parameter versioning: versione passata come parametro (/api/resource?v=1), comodo per test rapidi ma sconsigliato in produzione.

Breaking change: rimozione o rinomina campi, modifica tipi di dato, aggiunta di vincoli o campi obbligatori in request.

Additive change non-breaking: aggiunta di campi opzionali o nuove risorse, non richiede incremento di major version.

Semantic Versioning (SemVer): MAJOR.MINOR.PATCH, le API pubbliche espongono generalmente solo il MAJOR.

Sunset policy: header Deprecation e Sunset per notificare ai client la dismissione programmata di una versione.

Toll-free maintenance: supportare simultaneamente massimo due versioni attive per limitare il debito tecnico.

Domande tipiche e risposte pronte

Q: Come decidi se introdurre una nuova versione di un'API?R: La introduco solo in presenza di breaking change. Se l'evoluzione è additiva e backward-compatible, mantengo la versione corrente intatta.

Q: Qual è la differenza principale tra URI versioning e Content Negotiation?R: L'URI versioning cambia il path dell'endpoint ed è banale da cachare; la Content Negotiation usa l'header Accept preservando l'identità dell'URI della risorsa.

Q: Come gestisci la deprecazione di un endpoint in produzione?R: Uso gli standard HTTP header Sunset e Deprecation, definisco una migration window concordata e traccio l'uso residuo tramite metriche dedicate.

Insidie e errori comuni

Creare una nuova major version per semplici aggiunte additive retrocompatibili.

Modificare il tipo o il formato di un campo esistente senza bump di versione.

Duplicare l'intera base di codice tra versioni anziché isolare solo il layer di routing e serializzazione.

Non comunicare per tempo le scadenze di dismissione tramite header e comunicazioni esterne.

Caching scorretto sui proxy per versioning via header dovuto all'assenza dell'header Vary.

Snippet e comandiHTTP

// 1. URI Path Versioning
GET /api/v1/orders HTTP/1.1
Host: api.example.com

// 2. Custom Header Versioning
GET /api/orders HTTP/1.1
Host: api.example.com
X-API-Version: 2

// 3. Content Negotiation (Accept Header)
GET /api/orders HTTP/1.1
Host: api.example.com
Accept: application/vnd.app.v1+json

// 4. Response con Deprecation e Sunset (RFC 8594)
HTTP/1.1 200 OK
Content-Type: application/json
Deprecation: true
Sunset: Wed, 31 Dec 2026 23:59:59 GMT
Link: <https://api.example.com/v2/docs>; rel="successor-version"

TypeScript

// Esempio routing Express per gestione versioni
import express from 'express';
const app = express();

import v1Router from './routes/v1';
import v2Router from './routes/v2';

app.use('/api/v1', v1Router);
app.use('/api/v2', v2Router);

Da ripassare

[ ] Pattern di adapter o transformer per retrocompatibilità sui controller

[ ] Standard RFC 8594 per gli header Sunset e Deprecation

[ ] Impatto del versioning via header sul caching CDN e direttiva Vary

[x] Differenza tra modifiche additive e breaking changes

Jarvis Interviews
Jarvis