rest - spring versioning api




Best practice per il controllo delle versioni delle API? (5)

Esistono how-to o best practice noti per il controllo delle versioni dell'API REST del servizio Web?

Ho notato che AWS esegue il controllo delle versioni dall'URL dell'endpoint . È questo l'unico modo o ci sono altri modi per raggiungere lo stesso obiettivo? Se ci sono molti modi, quali sono i pregi di ogni modo?


Abbiamo trovato pratico e utile inserire la versione nell'URL. Rende facile capire cosa stai usando a colpo d'occhio. Facciamo alias / foo to / foo / (ultime versioni) per facilità d'uso, URL più brevi / più puliti, ecc., Come suggerisce la risposta accettata.

Mantenere la retrocompatibilità per sempre è spesso proibitivo dal punto di vista dei costi e / o molto difficile. Preferiamo dare un preavviso di deprecazione, reindirizzamenti come suggerito qui, documenti e altri meccanismi.


Concordo sul fatto che il controllo delle versioni della rappresentazione delle risorse segua meglio l'approccio REST ... ma, un grosso problema con i tipi MIME personalizzati (o tipi MIME che aggiungono un parametro di versione) è il supporto scarso per scrivere intestazioni Accept e Content-Type in HTML e JavaScript.

Ad esempio, non è possibile IMO to POST con le seguenti intestazioni nei moduli HTML5, al fine di creare una risorsa:

Accept: application/vnd.company.myapp-v3+json
Content-Type: application/vnd.company.myapp-v3+json 

Ciò è dovuto al fatto che l'attributo enctype HTML5 è un'enumerazione, quindi qualsiasi altra cosa diversa dalla solita application/x-www-formurlencoded , multipart/form-data e text/plain non sono validi.

... né sono sicuro che sia supportato su tutti i browser in HTML4 (che ha un attributo enctype più lassista, ma sarebbe un problema di implementazione del browser sul fatto che il tipo MIME sia stato inoltrato)

Per questo motivo ora sento che il modo più appropriato per la versione è tramite l'URI, ma accetto che non sia il modo "corretto".


Il controllo della versione dell'API REST è analogo al controllo di versione di qualsiasi altra API. Piccole modifiche possono essere apportate, modifiche importanti potrebbero richiedere una nuova API completa. Il modo più semplice per te è quello di ricominciare da zero ogni volta, il che è più appropriato quando inserire la versione nell'URL. Se vuoi semplificarti la vita per il client, provi a mantenere la compatibilità con le versioni precedenti, cosa che puoi fare con la deprecazione (reindirizzamento permanente), le risorse in diverse versioni ecc. Questo è più laborioso e richiede più impegno. Ma è anche ciò che incoraggia REST in "Gli URI cool non cambiano".

Alla fine è come qualsiasi altro progetto API. Pesare lo sforzo contro la comodità del cliente. Prendi in considerazione l'adozione del versioning semantico per la tua API, che rende chiaro per i tuoi clienti quanto sia retrocompatibile la tua nuova versione.


L'URL NON deve contenere le versioni. La versione non ha nulla a che fare con "idea" della risorsa che stai richiedendo. Dovresti cercare di pensare all'URL come a un percorso per il concetto che desideri - non a come vuoi che l'oggetto venga restituito. La versione detta la rappresentazione dell'oggetto, non il concetto dell'oggetto. Come hanno detto altri poster, dovresti specificare il formato (inclusa la versione) nell'intestazione della richiesta.

Se si guarda la richiesta HTTP completa per gli URL che hanno versioni, appare come questa:

(BAD WAY TO DO IT):

http://company.com/api/v3.0/customer/123
====>
GET v3.0/customer/123 HTTP/1.1
Accept: application/xml

<====
HTTP/1.1 200 OK
Content-Type: application/xml
<customer version="3.0">
  <name>Neil Armstrong</name>
</customer>

L'intestazione contiene la riga che contiene la rappresentazione richiesta ("Accept: application / xml"). Ecco dove dovrebbe andare la versione. Tutti sembrano sorvolare sul fatto che si potrebbe desiderare la stessa cosa in diversi formati e che il client dovrebbe poter chiedere quello che vuole. Nell'esempio precedente, il client richiede QUALSIASI rappresentazione XML della risorsa, non la vera rappresentazione di ciò che vuole. Il server potrebbe, in teoria, restituire qualcosa completamente estraneo alla richiesta fintanto che era XML e dovrebbe essere analizzato per rendersi conto che è sbagliato.

Un modo migliore è:

(GOOD WAY TO DO IT)

http://company.com/api/customer/123
===>
GET /customer/123 HTTP/1.1
Accept: application/vnd.company.myapp.customer-v3+xml

<===
HTTP/1.1 200 OK
Content-Type: application/vnd.company.myapp-v3+xml
<customer>
  <name>Neil Armstrong</name>
</customer>

Inoltre, diciamo che i clienti pensano che l'XML sia troppo prolisso e ora vogliono invece JSON. Negli altri esempi dovresti avere un nuovo URL per lo stesso cliente, quindi ti ritroveremmo con:

(BAD)
http://company.com/api/JSONv3.0/customers/123
  or
http://company.com/api/v3.0/customers/123?format="JSON"

(o qualcosa di simile). Quando infatti ogni richiesta HTTP contiene il formato che stai cercando:

(GOOD WAY TO DO IT)
===>
GET /customer/123 HTTP/1.1
Accept: application/vnd.company.myapp.customer-v3+json

<===
HTTP/1.1 200 OK
Content-Type: application/vnd.company.myapp-v3+json

{"customer":
  {"name":"Neil Armstrong"}
}

Usando questo metodo, hai molta più libertà nel design e aderisci effettivamente all'idea originale di REST. È possibile modificare le versioni senza interrompere i client o modificare i client in modo incrementale con la modifica delle API. Se si sceglie di interrompere il supporto di una rappresentazione, è possibile rispondere alle richieste con codice di stato HTTP o codici personalizzati. Il client può anche verificare che la risposta sia nel formato corretto e convalidare l'XML.

Ci sono molti altri vantaggi e ne discuto alcuni qui sul mio blog: http://thereisnorightway.blogspot.com/2011/02/versioning-and-types-in-resthttp-api.html

Un ultimo esempio per mostrare come mettere la versione nell'URL è brutto. Diciamo che volete qualche informazione all'interno dell'oggetto, e avete messo in versione i vostri vari oggetti (i clienti sono v3.0, gli ordini sono v2.0 e shipto object è v4.2). Ecco il brutto URL che devi fornire nel client:

(Another reason why version in the URL sucks)
http://company.com/api/v3.0/customer/123/v2.0/orders/4321/

Questa è una domanda buona e complicata. L'argomento del design URI è allo stesso tempo la parte più importante di un'API REST e , quindi, un impegno potenzialmente a lungo termine verso gli utenti di tale API .

Poiché l'evoluzione di un'applicazione e, in misura minore, la sua API è un fatto della vita e che è persino simile all'evoluzione di un prodotto apparentemente complesso come un linguaggio di programmazione, il design dell'URI dovrebbe avere vincoli meno naturali e dovrebbe essere preservato nel tempo . Maggiore è la durata dell'applicazione e dell'API, maggiore è l'impegno per gli utenti dell'applicazione e dell'API.

D'altra parte, un altro fatto della vita è che è difficile prevedere tutte le risorse e i loro aspetti che sarebbero stati consumati attraverso l'API. Fortunatamente, non è necessario progettare l'intera API che verrà utilizzata fino ad Apocalypse . È sufficiente definire correttamente tutti gli endpoint della risorsa e lo schema di indirizzamento di ogni istanza di risorsa e risorsa.

Nel tempo potrebbe essere necessario aggiungere nuove risorse e nuovi attributi a ciascuna particolare risorsa, ma il metodo che gli utenti API seguono per accedere a particolari risorse non dovrebbe cambiare una volta che uno schema di indirizzamento delle risorse diventa pubblico e quindi definitivo.

Questo metodo si applica alla semantica dei verbi HTTP (ad es. PUT dovrebbe sempre aggiornare / sostituire) e ai codici di stato HTTP supportati nelle precedenti versioni API (dovrebbero continuare a funzionare in modo che i client API che hanno funzionato senza intervento umano debbano poter continuare a lavorare come quello).

Inoltre, poiché l'incorporamento della versione API nell'URI interromperebbe il concetto di hypermedia come motore dello stato dell'applicazione (dichiarato nella tesi di dottorato di Roy T. Fieldings) avendo un indirizzo / URI di risorsa che cambierebbe nel tempo, concluderei che l' API le versioni non dovrebbero essere conservate negli URI delle risorse per un lungo periodo, il che significa che gli URI delle risorse che gli utenti API possono dipendere dovrebbero essere permalink .

Certo, è possibile incorporare la versione dell'API nell'URI di base, ma solo per usi ragionevoli e limitati come il debug di un client API che funziona con la nuova versione dell'API. Tali API con versioni dovrebbero essere limitate nel tempo e disponibili solo per gruppi limitati di utenti API (come durante le beta chiuse). Altrimenti, ti impegni dove non dovresti.

Un paio di considerazioni sulla manutenzione delle versioni API che hanno data di scadenza su di esse. Tutte le piattaforme / linguaggi di programmazione comunemente utilizzati per implementare servizi Web (Java, .NET, PHP, Perl, Rails, ecc.) Consentono un facile collegamento degli endpoint del servizio Web a un URI di base. In questo modo è facile raccogliere e mantenere una collezione di file / classi / metodi separati tra diverse versioni dell'API .

Dal punto di vista POV degli utenti API, è anche più facile lavorare con e associare a una particolare versione dell'API quando è ovvio, ma solo per un periodo limitato, ad esempio durante lo sviluppo.

Dal punto di vista del manutentore dell'API, è più facile mantenere in parallelo diverse versioni dell'API utilizzando i sistemi di controllo del codice sorgente che funzionano prevalentemente sui file come l'unità più piccola di controllo delle versioni (del codice sorgente).

Tuttavia, con le versioni API chiaramente visibili nell'URI c'è un avvertimento: si potrebbe anche obiettare questo approccio poiché la cronologia dell'API diventa visibile / aparente nella progettazione dell'URI e quindi è soggetta a cambiamenti nel tempo che va contro le linee guida di REST. Sono d'accordo!

Il modo per aggirare questa ragionevole obiezione è implementare la versione più recente dell'API con l'URI di base API senza versione. In questo caso, gli sviluppatori di client API possono scegliere tra:

  • svilupparsi contro l'ultimo (impegnandosi a mantenere l'applicazione proteggendolo da eventuali modifiche API che potrebbero interrompere il loro client API mal progettato ).

  • associare a una versione specifica dell'API (che diventa evidente) ma solo per un periodo limitato

Ad esempio, se l'API v3.0 è l'ultima versione dell'API, i seguenti due devono essere alias (ovvero comportarsi in modo identico a tutte le richieste API):

http://shonzilla/api/customers/1234
http://shonzilla/api/v3.0/customers/1234
http://shonzilla/api/v3/customers/1234

Inoltre, i client API che tentano ancora di puntare alla vecchia API devono essere informati di utilizzare la versione dell'ultima API precedente, se la versione dell'API che stanno utilizzando è obsoleta o non è più supportata . Quindi, accedendo a uno qualsiasi degli URI obsoleti come questi:

http://shonzilla/api/v2.2/customers/1234
http://shonzilla/api/v2.0/customers/1234
http://shonzilla/api/v2/customers/1234
http://shonzilla/api/v1.1/customers/1234
http://shonzilla/api/v1/customers/1234

deve restituire uno qualsiasi dei codici di stato HTTP 30x che indicano il reindirizzamento utilizzato insieme all'intestazione Location HTTP che reindirizza alla versione appropriata dell'URI della risorsa che rimane tale:

http://shonzilla/api/customers/1234

Esistono almeno due codici di stato HTTP di reindirizzamento appropriati per gli scenari di versioning delle API:

  • 301 Spostato in modo permanente che indica che la risorsa con un URI richiesto viene spostata in modo permanente in un altro URI (che dovrebbe essere un permalink di istanza di risorsa che non contiene informazioni sulla versione dell'API). Questo codice di stato può essere utilizzato per indicare una versione API obsoleta / non supportata, informando il client API che un URI di risorsa versione è stato sostituito da un permalink di risorsa .

  • 302 Trovato che indica che la risorsa richiesta si trova temporaneamente in un'altra posizione, mentre l'URI richiesto potrebbe ancora essere supportato. Questo codice di stato può essere utile quando gli URI versione-less sono temporaneamente non disponibili e che una richiesta deve essere ripetuta usando l'indirizzo di reindirizzamento (es. Indicando l'URI con la versione APi incorporata) e vogliamo dire ai clienti di continuare ad usarlo (es. permalink).

  • altri scenari possono essere trovati nel capitolo Redirection 3xx della specifica HTTP 1.1





versioning