Come eseguire la versione degli URI REST


111

Qual è il modo migliore per eseguire la versione degli URI REST? Attualmente abbiamo una versione # nell'URI stesso, cioè.

http://example.com/users/v4/1234/

per la versione 4 di questa rappresentazione.

La versione appartiene a queryString? vale a dire.

http://example.com/users/1234?version=4

O il controllo delle versioni si ottiene in un altro modo?


Risposte:


34

Direi che è meglio renderlo parte dell'URI stesso (opzione 1) perché la v4 identifica una risorsa diversa dalla v3. I parametri di query come nella seconda opzione possono essere utilizzati al meglio per trasferire informazioni aggiuntive (query) relative alla richiesta , piuttosto che alla risorsa .


11
La domanda è: stiamo discutendo di una RISORSA diversa? O una diversa rappresentazione di quella risorsa? REST fa una distinzione tra la rappresentazione e la risorsa?
Cheeso,

1
@Cheeso - L'OP indica che si tratta di una rappresentazione diversa piuttosto che una risorsa diversa, da cui la mia risposta.
Greg Beech,

Questa è stata risolta in un dettaglio maggiore, prima qui stackoverflow.com/q/389169/104261
Taras Alenin

+1 per "I parametri di query come nella seconda opzione possono essere utilizzati al meglio per trasmettere informazioni aggiuntive (query) relative alla richiesta, piuttosto che alla risorsa"
andy

Per diverse rappresentazioni penso che dovresti usare intestazioni come "Accetta", quindi il client può specificare al server "Accetto solo versione 4" e il server può rispondere con quella rappresentazione. Se non viene inviata alcuna accettazione, viene fornita l'ultima versione.
Carlos Verdes

190

Non versione URL, perché ...

  • rompi i permalink
  • Le modifiche all'URL si diffonderanno come una malattia attraverso la tua interfaccia. Cosa fai delle rappresentazioni che non sono cambiate ma che puntano alla rappresentazione che ha? Se cambi l'URL, rompi i vecchi client. Se lasci l'URL, i tuoi nuovi client potrebbero non funzionare.
  • Il controllo delle versioni dei tipi di supporto è una soluzione molto più flessibile.

Supponendo che la tua risorsa stia restituendo una variante di application / vnd.yourcompany.user + xml, tutto ciò che devi fare è creare il supporto per un nuovo tipo di supporto application / vnd.yourcompany.userV2 + xml e attraverso la magia della negoziazione del contenuto il tuo v1 e I client v2 possono coesistere pacificamente.

In un'interfaccia RESTful, la cosa più vicina a un contratto è la definizione dei tipi di media che vengono scambiati tra il client e il server.

Gli URL che il client utilizza per interagire con il server dovrebbero essere forniti dal server incorporato in rappresentazioni recuperate in precedenza. L'unico URL che deve essere conosciuto dal client è l'URL principale dell'interfaccia. L'aggiunta di numeri di versione agli URL ha valore solo se costruisci gli URL sul client, cosa che non dovresti fare con un'interfaccia RESTful.

Se hai bisogno di apportare una modifica ai tuoi tipi di media che interromperà i tuoi client esistenti, creane uno nuovo e lascia i tuoi URL da soli!

E per quei lettori che attualmente dicono che questo non ha senso se sto usando application / xml e application / json come tipi di media. Come dovremmo rivederli? Tu non sei. Questi tipi di media sono praticamente inutili per un'interfaccia RESTful a meno che non li analizzi usando il download del codice, a quel punto il controllo delle versioni è un punto controverso.


66
Per affrontare i punti elenco. 1. non interrompi i collegamenti perma, perché i permalink si collegano a una versione specifica 2. Se tutto ha una versione, questo non è un problema. I vecchi URL possono ancora funzionare. Idealmente, non vorresti che un URL della versione 4 restituisse un'associazione a una risorsa della versione 3. 3. Forse
Mike Pone,

10
Immagina se quando esegui l'upgrade a una nuova versione di un browser web, tutti i tuoi preferiti aggiunti ai preferiti si rompessero! Ricorda che concettualmente l'utente sta salvando un collegamento a una risorsa, non a una versione di una rappresentazione di una risorsa.
Darrel Miller,

11
@Gili Per soddisfare il requisito che un'api REST sia auto-descrittiva è necessario che l'intestazione del tipo di contenuto fornisca la descrizione semantica completa del messaggio. In altre parole, il tuo tipo di media è il tuo contratto dati. Se fornisci application / xml o application / json non stai dicendo al client nulla su ciò che è contenuto in tale XML / Json. L'istante in cui un'applicazione client raggiunge in un pull out / Customer / Name si sta creando un accoppiamento basato su informazioni che non sono nel messaggio. L'eliminazione dell'accoppiamento fuori banda è fondamentale per ottenere il RESTfulness.
Darrel Miller,

6
@Gili Il client non dovrebbe avere alcuna conoscenza preliminare degli URL dell'API diversi dall'URL radice. Non collegare i formati di rappresentazione a URL specifici. Quando si tratta di scegliere i tipi di media, è davvero necessario scegliere tra un formato specifico come application / vnd.mycompany.myformat + xml o uno standardizzato come XHtml, Atom, RDF, ecc.
Darrel Miller,

4
Ha senso mettere la versione API come un campo di intestazione separato? In questo modo: Accetta: application / com.example.myapp + json; versione = 1.0
Erik

21

Ah, mi metto di nuovo il mio vecchio cappello burbero.

Dal punto di vista di ReST, non importa affatto. Non una salsiccia.

Il client riceve un URI che desidera seguire e lo tratta come una stringa opaca. Mettici quello che vuoi, il client non è a conoscenza di una cosa come un identificatore di versione su di esso.

Quello che il cliente sa è che può elaborare il tipo di media e io consiglierò di seguire il consiglio di Darrel. Inoltre, personalmente ritengo che la necessità di modificare il formato utilizzato in un'architettura riposante 4 volte dovrebbe portare enormi e massicci segnali di avvertimento che stai facendo qualcosa di gravemente sbagliato e aggirando completamente la necessità di progettare il tuo tipo di supporto per la resilienza al cambiamento.

In ogni caso, il client può elaborare solo un documento con un formato comprensibile e seguire i collegamenti al suo interno. Dovrebbe conoscere le relazioni di collegamento (le transizioni). Quindi cosa c'è nell'URI è completamente irrilevante.

Personalmente voterei per http: // localhost / 3f3405d5-5984-4683-bf26-aca186d21c04

Un identificatore perfettamente valido che impedirà a qualsiasi ulteriore sviluppatore client o persona di toccare il sistema per chiedersi se si debba mettere v4 all'inizio o alla fine di un URI (e suggerisco che, dal punto di vista del server, non dovresti averne 4 versioni, ma 4 tipi di supporto).


E se la rappresentazione dovesse cambiare in modo significativo e non fosse retrocompatibile?
Mike Pone,

1
Progettando il tipo di supporto in modo estensibile, ad esempio utilizzando spazi dei nomi e un xsd estensibile o formati xml esistenti ike atom, questo dovrebbe essere prevenibile. Se proprio devi, un altro tipo di media è la strada da percorrere.
SerialSeb

1
Mi piace questa risposta completamente valida, ma penso che l'URI proposto sia più per dimostrare il punto che per uno scenario reale in cui si vogliono URI "hackerabili".
Dave Van den Eynde

10

NON dovresti mettere la versione nell'URL, dovresti mettere la versione nell'intestazione di accettazione della richiesta - vedi il mio post su questo thread:

Best practice per il controllo delle versioni delle API?

Se inizi a incollare versioni nell'URL, finisci con URL stupidi come questo: http://company.com/api/v3.0/customer/123/v2.0/orders/4321/

E ci sono anche un sacco di altri problemi che si insinuano - vedi il mio blog: http://thereisnorightway.blogspot.com/2011/02/versioning-and-types-in-resthttp-api.html


11
Mi dispiace, ma non credo che ti ritroverai con URL stupidi come questo. Stai legando i numeri di versione a una particolare risorsa o (peggio) a una particolare rappresentazione. Sarebbe sciocco, IMO. Piuttosto, stai eseguendo il controllo delle versioni dell'API, quindi non avresti mai più di una versione nell'URI.
fool4jesus


3

Esistono 4 diversi approcci al controllo delle versioni dell'API:

  • Aggiunta della versione al percorso dell'URI:

    http://example.com/api/v1/foo
    
    http://example.com/api/v2/foo
    

    Quando si hanno modifiche di rilievo, è necessario incrementare la versione come: v1, v2, v3 ...

    Puoi implementare un controller nel tuo codice come questo:

    @RestController
    public class FooVersioningController {
    
    @GetMapping("v1/foo")
    public FooV1 fooV1() {
        return new FooV1("firstname lastname");
    }
    
    @GetMapping("v2/foo")
    public FooV2 fooV2() {
        return new FooV2(new Name("firstname", "lastname"));
    }
    
  • Richiedi controllo delle versioni dei parametri:

    http://example.com/api/v2/foo/param?version=1
    http://example.com/api/v2/foo/param?version=2
    

    Il parametro della versione può essere facoltativo o obbligatorio a seconda di come si desidera utilizzare l'API.

    L'implementazione può essere simile a questa:

    @GetMapping(value = "/foo/param", params = "version=1")
    public FooV1 paramV1() {
        return new FooV1("firstname lastname");
    }
    
    @GetMapping(value = "/foo/param", params = "version=2")
    public FooV2 paramV2() {
        return new FooV2(new Name("firstname", "lastname"));
    }
    
  • Passaggio di un'intestazione personalizzata:

    http://localhost:8080/foo/produces
    

    Con intestazione:

    headers[Accept=application/vnd.company.app-v1+json]
    

    o:

    headers[Accept=application/vnd.company.app-v2+json]
    

    Il vantaggio più grande di questo schema è principalmente la semantica: non stai ingombrando l'URI con nulla a che fare con il controllo delle versioni.

    Possibile implementazione:

    @GetMapping(value = "/foo/produces", produces = "application/vnd.company.app-v1+json")
    public FooV1 producesV1() {
        return new FooV1("firstname lastname");
    }
    
    @GetMapping(value = "/foo/produces", produces = "application/vnd.company.app-v2+json")
    public FooV2 producesV2() {
        return new FooV2(new Name("firstname", "lastname"));
    }
    
  • Modifica dei nomi host o utilizzo di gateway API:

    In sostanza, stai spostando l'API da un nome host a un altro. Potresti anche chiamare questo edificio di una nuova API per le stesse risorse.

    Inoltre, puoi farlo utilizzando i gateway API.


2

Se i servizi REST richiedono l'autenticazione prima dell'uso, è possibile associare facilmente la chiave / token API a una versione API ed eseguire il routing internamente. Per utilizzare una nuova versione dell'API, potrebbe essere necessaria una nuova chiave API, collegata a quella versione.

Sfortunatamente, questa soluzione funziona solo per le API basate sull'autenticazione. Tuttavia, mantiene le versioni fuori dagli URI.



1

Includerei la versione come valore facoltativo alla fine dell'URI. Potrebbe essere un suffisso come / V4 o un parametro di query come hai descritto. Potresti persino reindirizzare / V4 al parametro della query in modo da supportare entrambe le varianti.


1

Se utilizzi gli URI per il controllo delle versioni, il numero di versione dovrebbe essere nell'URI della radice dell'API, quindi ogni identificatore di risorsa può includerlo.

Tecnicamente un'API REST non viene interrotta dalle modifiche dell'URL (il risultato del vincolo di interfaccia uniforme). Si interrompe solo quando la relativa semantica (ad esempio un vocabolario RDF specifico dell'API) cambia in modo non compatibile con le versioni precedenti (raro). Attualmente molti ppl non usano collegamenti per la navigazione (vincolo HATEOAS) e vocab per annotare le loro risposte REST (vincolo di messaggio auto-descrittivo), ecco perché i loro clienti falliscono.

I tipi MIME personalizzati e il controllo delle versioni dei tipi MIME non aiutano, perché l'inserimento dei metadati correlati e della struttura della rappresentazione in una stringa breve non funziona. Ofc. i metadati e la struttura cambieranno frequentemente, quindi anche il numero di versione ...

Quindi, per rispondere alla tua domanda, il modo migliore per annotare le tue richieste e risposte con i vocaboli ( Hydra , linked data ) e dimenticare il versioning o usarlo solo con modifiche al vocabolario non retrocompatibili (ad esempio se vuoi sostituire un vocabolario con un altro).


0

Voto a favore di farlo in MIME ma non in URL. Ma il motivo non è lo stesso degli altri ragazzi.

Penso che l'URL dovrebbe essere univoco (ad eccezione di quei reindirizzamenti) per individuare la risorsa unica. Quindi, se accetti /v2.0negli URL, perché non è /ver2.0o /v2/o /v2.0.0? O anche -alphae -beta? (quindi diventa totalmente il concetto di semver )

Quindi, la versione in tipo MIME è più accettabile dell'URL.

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.