Utilizzo dei dati per mantenere la compatibilità durante l'evoluzione del servizio RESTful

2

Ho letto le versioni delle API per le API REST.

La maggior parte degli articoli che ho trovato ( ecco un esempio ) sembrano concentrarsi su due opzioni:

  1. Controllo delle versioni basato su URI, ad es. %codice%
  2. Tipo di versione del supporto multimediale, ad esempio aggiungendo ulteriori informazioni all'intestazione v1/my_resource/ .

Ho anche visto proposte di aggiungere un parametro o un'intestazione di versione personalizzata.

In generale, però, da un punto di vista filosofico, uno sembra finire in territorio non riposante con significative implicazioni complessità e caching, e puritani resto sarebbe insistono sul fatto che il controllo delle versioni è sbagliato ed è necessario per mantenere la compatibilità all'indietro ( ecco le parole di Roy Felding sull'argomento ).

Una cosa che non ho visto menzionata è l'utilizzo del carico utile dei dati come soluzione al problema della modifica delle funzionalità mantenendo la compatibilità con le versioni precedenti.

Prendi il seguente corpo JSON di esempio:

{
  "v15": { 
    "field2": "abc",
    "field3": 42
  },
  "v14": {
    "field1": "code still supports me",
    "field2": "abc"
  }
} 

L'idea qui è di avere i nuovi utenti API che agiscono sui dati v15 e i vecchi utenti otterranno comunque i loro dati v14 richiesti ignorando i dati v (n > 14) in base alla progettazione. Naturalmente, lo svantaggio è che sia il codice produttore che il codice cliente dovranno essere in grado di gestire due o più versioni dei dati.

Tuttavia, il compromesso a prima vista mi sembra attraente. Sono scettico, tuttavia, poiché non ho visto questa soluzione descritta in nessun articolo che ho trovato.

La mia domanda è: cosa mi manca? Questa è una pessima soluzione per l'evoluzione di un servizio?

    
posta Erik Madsen 13.09.2018 - 12:47
fonte

3 risposte

1

Is this a bad solution for evolving a service?

No, ma richiede più cura e attenzione.

(REST non entra realmente nel problema, che è il problema più generale dei messaggi).

Se i client e i server saranno implementabili in modo indipendente, allora dovremo affrontare il seguente problema: un cliente dell'anno: 2017 deve essere compreso da un server dell'anno: 2016, un server dall'anno: 2017 e un server dall'anno :. 2018

Presumibilmente cliente: dal 2017 al server: il 2017 è banale - entrambi utilizzano la definizione del messaggio del 2017, e quindi possono capirsi perfettamente.

Ma come possiamo organizzare che il cliente possa parlare ai server passati e futuri? O (a) la definizione deve essere completamente fissata per tutto il tempo, o (b) il modo in cui il messaggio si evolve nel tempo deve essere limitato.

Più precisamente, abbiamo bisogno di descrivere il modello di elaborazione del messaggio in modo tale che le cose sensate accadano quando il produttore e il consumatore non usano esattamente lo stesso schema.

In genere ciò significa che

  • gli elementi obbligatori sono corretti
  • Gli elementi
  • non vengono mai riproposti (invece, crea un nuovo elemento)
  • possono essere aggiunti elementi facoltativi, con un valore specificato da utilizzare in assenza dell'elemento
  • gli elementi non riconosciuti vengono ignorati

Quindi, se il client invia un messaggio con elementi facoltativi {A,B}

... then server: 2016, che non conosce l'elemento B, lo ignora semplicemente.

... then server: 2017, entrambi gli elementi A e B

... then server: 2018, usa gli elementi A e B , e anche il valore predefinito specificato per l'elemento C .

C'è un sacco di materiale disponibile che discute queste idee in dettaglio

risposta data 13.09.2018 - 16:01
fonte
2

Sì, è una cattiva soluzione per l'evoluzione di un servizio.

La chiave del modo in cui invii le informazioni sulla versione è che può modificare il routing della richiesta.

Vuoi avere la tua versione 14 api su una scatola diversa per la tua versione 15 api e utilizzare le informazioni sulla richiesta in arrivo per decidere su quale casella inviare la richiesta.

Un hostname, intestazione o percorso url può essere prelevato da load balancers o web server abbastanza facilmente e utilizzato a tale scopo.

Tuttavia, se tali informazioni sono incorporate nel corpo della richiesta come parte del json, è molto più difficile da ottenere. Certo, puoi programmare un'API per analizzare il json e capire il numero di versione, ma puoi impostare una regola ACL HAProxy per farlo?

Inoltre dovrei aggiungere, non vuoi davvero che i consumatori api debbano preoccuparsi troppo della versione. Idealmente dovrebbero essere in grado di non specificare una versione e ottenere l'ultima versione.

Ecco perché preferisco il metodo di intestazione della versione. L'interfaccia API può rimanere ignorante di altre versioni, ma i consumatori che desiderano una versione specifica possono aggiungere l'intestazione come richiesto.

Un altro avvertimento importante. Il controllo delle versioni dei dati è una cosa e potrebbe essere necessario eseguire la versione dei tuoi anche come tua API. soprattutto se si stanno elaborando dati che sono stati intorno a un tempo di attesa. Ma normalmente un v14 api sarà in grado di assumere in sicurezza dati v14

    
risposta data 13.09.2018 - 13:01
fonte
1

Dovresti lavorare per mantenere la compatibilità al contrario entro la ragione .

Non penso che Roy Felding stia necessariamente discutendo contro la rottura delle modifiche quando è necessario per evolvere l'applicazione.

La migliore soluzione per il controllo delle versioni dei servizi REST che ho visto (e utilizzato come consumatore) consiste nel specificare un parametro querystring. Ad esempio, i servizi Microsoft accettano un parametro api-version che consente loro di instradare la richiesta alla versione corretta del servizio.

Se si specifica api-version=4.1-preview.3 , è perfettamente chiaro quale versione del servizio dovrebbe essere utilizzata.

Il problema più grande che vedo con il tuo approccio è come il tuo cliente genererebbe il tuo corpo della richiesta. Avrai un serializzatore che è a conoscenza di diverse versioni del modello e popola in qualche modo i campi corretti usati da ciascuna versione.

È molto più semplice quando il tuo cliente comprende semplicemente una versione e non deve tenere conto delle versioni.

    
risposta data 13.09.2018 - 16:17
fonte