Best practice per il versioning delle API? [chiuso]


877

Esistono procedure o procedure consigliate per il controllo delle versioni dell'API REST del servizio Web?

Ho notato che AWS esegue il controllo delle versioni tramite l'URL dell'endpoint . È l'unico modo o ci sono altri modi per raggiungere lo stesso obiettivo? Se ci sono più modi, quali sono i vantaggi di ciascun modo?

Risposte:


682

Questa è una domanda buona e difficile. L'argomento della progettazione di URI è allo stesso tempo la parte più importante di un'API REST e , pertanto, un impegno potenzialmente a lungo termine nei confronti degli utenti di tale API .

Poiché l'evoluzione di un'applicazione e, in misura minore, la sua API è un dato di fatto e che è persino simile all'evoluzione di un prodotto apparentemente complesso come un linguaggio di programmazione, il design dell'URI dovrebbe avere meno vincoli 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 verrebbero consumati attraverso l'API. Fortunatamente, non è necessario progettare l'intera API che verrà utilizzata fino al Apocalypse . È sufficiente definire correttamente tutti gli end-point e lo schema di indirizzamento di ogni risorsa e istanza di 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 una particolare risorsa non dovrebbe cambiare una volta che uno schema di indirizzamento delle risorse diventa pubblico e quindi definitivo.

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

Inoltre, poiché l'incorporazione della versione dell'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 devono essere mantenute a lungo negli URI delle risorse, il che significa che gli URI delle risorse su cui gli utenti API possono fare affidamento dovrebbero essere permalink .

Certo, è possibile incorporare la versione 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 versione devono 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 pensieri riguardanti la manutenzione delle versioni API che hanno una data di scadenza. Tutte le piattaforme / i linguaggi di programmazione comunemente utilizzati per implementare i servizi Web (Java, .NET, PHP, Perl, Rails, ecc.) Consentono un facile collegamento degli endpoint dei servizi Web a un URI di base. In questo modo è facile raccogliere e mantenere una raccolta di file / classi / metodi separati tra le diverse versioni dell'API .

Dal punto di vista degli utenti API, è anche più facile lavorare e associarsi a una particolare versione dell'API quando è ovvio ma solo per un tempo limitato, cioè durante lo sviluppo.

Dal POV del manutentore dell'API, è più semplice mantenere in parallelo diverse versioni dell'API utilizzando sistemi di controllo del codice sorgente che funzionano principalmente sui file come la più piccola unità di controllo delle versioni (codice sorgente).

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

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

  • sviluppare rispetto a quello più recente (impegnandosi a mantenere l'applicazione proteggendola da eventuali modifiche all'API che potrebbero interrompere il client API mal progettato ).

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

Ad esempio, se API v3.0 è l'ultima versione dell'API, i seguenti due dovrebbero 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 per utilizzare l'ultima versione dell'API precedente, se la versione dell'API che stanno utilizzando è obsoleta o non più supportata . Quindi accedere 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

dovrebbe restituire uno qualsiasi dei 30x codici di stato HTTP che indicano il reindirizzamento utilizzato insieme aLocation HTTP che reindirizza alla versione appropriata dell'URI della risorsa che rimane questa:

http: // shonzilla / api / clienti / 1234

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

  • 301 Spostato in modo permanente indicando che la risorsa con un URI richiesto viene spostata permanentemente 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 risorse con versione è stato sostituito da un permalink di risorse .

  • 302 trovati 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 senza versione sono temporaneamente non disponibili e che una richiesta deve essere ripetuta utilizzando l'indirizzo di reindirizzamento (ad es. Puntando all'URI con la versione APi incorporata) e vogliamo dire ai clienti di continuare a usarlo (ad es. permalink).

  • altri scenari sono disponibili nel capitolo Redirection 3xx della specifica HTTP 1.1


142
L'uso di un numero di versione nell'URL non deve essere considerato una cattiva pratica quando l'implementazione sottostante cambia. "Quando l'interfaccia a un servizio cambia in modo non compatibile con le versioni precedenti, in realtà è stato creato un servizio completamente nuovo ... Dal punto di vista del cliente, un servizio non è altro che un'interfaccia e alcune qualità non funzionali. .se l'interfaccia a un servizio cambia in modo non compatibile con le versioni precedenti, non rappresenta più un'istanza del servizio originale, ma è piuttosto un servizio completamente nuovo. " ibm.com/developerworks/webservices/library/ws-version
benvolioT

7
Hai qualche idea sull'aggiunta di un'intestazione con il numero di versione in modo che possa essere verificato da client o sviluppatori?
webclimber,

11
Vedi anche l'uso di un'intestazione Accept per indicare la versione che il client si aspetta: blog.steveklabnik.com/2011/07/03/…
Weston Ruter,

52
Per l'ultima parte: direi che un'API obsoleta e non più supportata dovrebbe tornare 410 Gone, poiché un reindirizzamento potrebbe indicare che la nuova posizione è compatibile quando non lo è. Se l'API è semplicemente obsoleta ma esiste ancora, Warningun'intestazione HTTP sulla risposta potrebbe essere un'opzione.
Michael Stum

22
Come gestisci i client che stanno già utilizzando l'URL stabile come shonzilla / api / customers / 1234 e desideri eseguire l'aggiornamento a una nuova versione? come puoi forzarli ad aggiungere il V2 (quello vecchio) all'URL?
Dejell l'

273

L'URL NON deve contenere le versioni. La versione non ha nulla a che fare con l '"idea" della risorsa che stai richiedendo. Dovresti provare a considerare l'URL come un percorso verso il concetto che desideri, non come desideri che l'articolo venga restituito. La versione detta la rappresentazione dell'oggetto, non il concetto dell'oggetto. Come hanno affermato altri poster, dovresti specificare il formato (compresa la versione) nell'intestazione della richiesta.

Se guardi la richiesta HTTP completa per gli URL che hanno versioni, è simile al seguente:

(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 ("Accetta: application / xml"). Ecco dove dovrebbe andare la versione. Tutti sembrano ignorare il fatto che potresti desiderare la stessa cosa in diversi formati e che il cliente dovrebbe essere in grado di chiedere quello che vuole. Nell'esempio sopra, il client chiede QUALSIASI rappresentazione XML della risorsa, non proprio la vera rappresentazione di ciò che vuole. Il server potrebbe, in teoria, restituire qualcosa di completamente estraneo alla richiesta purché fosse 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, supponiamo che i client pensino che l'XML sia troppo dettagliato e che ora preferiscano JSON. Negli altri esempi dovresti avere un nuovo URL per lo stesso cliente, quindi finirai 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). In realtà, 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 stai aderendo all'idea originale di REST. È possibile modificare le versioni senza interrompere i client o modificare in modo incrementale i client man mano che le API vengono modificate. 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 non è corretto inserire la versione nell'URL. Diciamo che vuoi alcune informazioni all'interno dell'oggetto e che hai eseguito la versione dei vari oggetti (i clienti sono v3.0, gli ordini sono v2.0 e shipto object è v4.2). Ecco l'URL brutto 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/

10
Gestire la versione del contratto di dati indipendente e le versioni del contratto di servizio nell'intestazione Accept sembra un disordine tanto quanto è disordinato nell'URL. Ci sono altre opzioni? Inoltre, se ho più endpoint (soap, resto), questo dovrebbe essere indicato anche in Accetta e lasciare che il servizio di routing all'estremità del server decida la direzione verso l'endpoint corretto O è accettabile che l'endpoint sia codificato nell'URL?
ideafountain

117
Non posso essere d'accordo con questo, almeno fino al punto del tuo ultimo motivo. Questo sembra dire che le diverse parti dell'URI hanno versioni diverse. Ma non è questo il punto di una versione dell'API. Il punto è avere UNA versione per TUTTA la risorsa. Se cambi versione, è una risorsa API diversa. Ecco perché non ha senso vedere company.com/api/v3.0/customer/123/v2.0/orders/4321 ma piuttosto company.com/api/v3.0/customer/123/orders/4321 Non esegui il controllo delle versioni di una determinata parte della risorsa, esegui il controllo delle versioni della risorsa nel suo insieme.
fool4jesus

90
Semmanticamente usare il numero di versione nell'intestazione sembra migliore. Ma è molto più pratico usare l'URL: meno soggetto a errori, meglio sottoposto a debug, facilmente visibile dagli sviluppatori, facilmente modificabile nel resto testare i client.
Daniel Cerecedo,

7
Penso che il MALE / BUONO semplifichi la domanda. L'API sta per "Interfaccia di programmazione dell'applicazione" e le interfacce di versioning sembrano essere un'ottima idea. Le API non riguardano solo la gestione delle risorse. Ciò che deve essere separato è che alcune persone parlano di interfacce e altre persone parlano di risorse. Se osservi attentamente le API di google maps nella scheda di rete, vedrai che includono il numero di versione di api nell'URL. Ad esempio: maps.google.com/maps/api/jsv2 durante l'autenticazione. Jsv2 è il numero api.
Tom Gruner,

6
@Gili: In realtà, non dovresti più usarlo -xperché è deprecato da RFC6648 .
Jonathan W

98

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

Mantenere la compatibilità con le versioni precedenti per sempre è spesso proibitiva in termini di costi e / o molto difficile. Preferiamo dare un preavviso di deprecazione, reindirizzamenti come suggerito qui, documenti e altri meccanismi.


5
La risposta accettata può essere la più corretta e pura. Tuttavia, per lo sviluppatore e l'utente quotidiano delle API, questo è sicuramente il più semplice da usare e configurare. L'approccio più pragmatico. Come indicato da altri Google e Amazon anche utilizzare questo approccio.
Muhammad Rehan Saeed,

46

Concordo sul fatto che il versioning 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) è lo scarso supporto per scrivere nelle intestazioni Accept e Content-Type in HTML e JavaScript.

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

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

Questo perché il HTML5 enctypeattributo è un'enumerazione, quindi qualcosa di diverso dal solito application/x-www-formurlencoded, multipart/form-datae text/plainnon sono validi.

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

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


14
Supponendo il percorso in cui è stato definito il versioning nelle intestazioni, si potrebbe dire che i moduli HTML che utilizzano l'invio di moduli nativi utilizzerebbero sempre l'ultima versione dell'API poiché non passerebbero la versione specifica a cui vogliono aderire. Tuttavia, le richieste XHR consentono effettivamente di modificare le accettazioni e leggere le intestazioni del tipo di contenuto. Quindi le forme di base sono davvero l'unico problema.
Kyle Hayes,

Non sono sicuro di essere d'accordo sul fatto che l'URI sia il più appropriato, ma il fatto che Content-Type non funzioni con i moduli è davvero molto importante.
wprl

2
@Kyle, ho visto un blog da qualche parte che ha detto che se non si specifica una versione nell'intestazione della richiesta, è meglio tornare con la prima versione di API non l'ultima per la migliore compatibilità.
andy,

Questo in realtà ha molto senso per me ora che ci penso.
Kyle Hayes,

@KyleHayes non dimenticare iframe, video / embed e altri tag di tipo "src / href".
visita il

21

Inserisci la tua versione nell'URI. Una versione di un'API non supporterà sempre i tipi da un'altra, quindi l'argomento secondo cui le risorse vengono semplicemente migrate da una versione all'altra è semplicemente sbagliato. Non è lo stesso del passaggio dal formato XML a JSON. I tipi potrebbero non esistere o potrebbero essere cambiati semanticamente.

Le versioni fanno parte dell'indirizzo della risorsa. Stai eseguendo il routing da un'API all'altra. Non è RESTful nascondere l'indirizzamento nell'intestazione.


13

Esistono alcuni punti in cui è possibile eseguire il controllo delle versioni in un'API REST:

  1. Come notato, nell'URI. Questo può essere trattabile e persino esteticamente piacevole se i reindirizzamenti e simili sono usati bene.

  2. Nell'intestazione Accetta: quindi la versione è nel tipo di file. Come 'mp3' vs 'mp4'. Funzionerà anche questo, sebbene IMO funzioni un po 'meno bene di ...

  3. Nella risorsa stessa. Molti formati di file hanno i loro numeri di versione incorporati, in genere nell'intestazione; ciò consente al software più recente di "funzionare" semplicemente comprendendo tutte le versioni esistenti del tipo di file, mentre il software più vecchio può puntare se viene specificata una versione non supportata (più recente). Nel contesto di un'API REST, significa che i tuoi URI non devono mai cambiare, solo la tua risposta alla particolare versione dei dati che ti è stata consegnata.

Vedo i motivi per utilizzare tutti e tre gli approcci:

  1. se ti piace fare nuove API "pulite" o per importanti cambiamenti di versione in cui desideri un tale approccio.
  2. se si desidera che il client sappia prima che esegue un PUT / POST se funzionerà o meno.
  3. se va bene se il client deve fare il suo PUT / POST per scoprire se funzionerà.

8

Il controllo delle versioni dell'API REST è analogo al controllo delle versioni di qualsiasi altra API. Possono essere apportate modifiche minori, modifiche importanti potrebbero richiedere un'intera nuova API. La cosa più semplice per te è ricominciare da capo ogni volta, il che è quando mettere la versione nell'URL ha più senso. Se vuoi semplificare la vita al cliente, prova a mantenere la retrocompatibilità, cosa che puoi fare con deprecazione (reindirizzamento permanente), risorse in diverse versioni ecc. Questo è più complicato e richiede più sforzo. Ma è anche ciò che REST incoraggia in "Gli URI fantastici non cambiano".

Alla fine è proprio come qualsiasi altro design API. Pesare lo sforzo contro la convenienza del cliente. Prendi in considerazione l'adozione del controllo delle versioni semantico per la tua API, il che chiarisce ai tuoi clienti quanto sia compatibile la tua nuova versione con le versioni precedenti.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.