Compatibilità

Questa pagina fornisce spiegazioni più dettagliate sull'elenco di interruzioni modifiche non permanenti specificate nella sezione Controllo delle versioni.

Non è sempre assolutamente chiaro cosa si intende per modifica che comporta una interruzione (incompatibile). Le linee guida qui riportate devono essere considerate indicative anziché un elenco completo di tutte le possibili modifiche.

Le regole elencate qui riguardano solo la compatibilità del client. È ci si aspetta che i produttori di API siano consapevoli dei propri requisiti in materia al deployment, incluse le modifiche ai dettagli dell'implementazione.

L'obiettivo generale è fare in modo che i clienti non vengano interrotti da un servizio che si aggiorna a una nuova versione secondaria o patch. I tipi di interruzioni presi in considerazione sono:

  • Compatibilità dell'origine: codice scritto sulla base 1.0 non compilata rispetto alla versione 1.1
  • Compatibilità binaria: il codice compilato sulla versione 1.0 non riesce a collegarsi/eseguito su un 1.1. I dettagli esatti dipendono dalla piattaforma client; esistono varianti di questo in situazioni diverse.
  • Compatibilità con i cavi: un'applicazione basata sulla versione 1.0 che non comunica con un server 1.1
  • Compatibilità semantica: tutto funziona, ma i risultati sono indesiderati o sorprendenti

In altre parole: i vecchi client dovrebbero essere in grado di lavorare su server più recenti all'interno dello stesso numero di versione principale e quando desiderano eseguire l'aggiornamento una versione secondaria (ad esempio per sfruttare una nuova funzionalità), dovrebbero essere possano farlo facilmente.

Nota: quando facciamo riferimento a numeri di versione come v1.1 e v1.0, otteniamo che fanno riferimento a numeri logici di versione che non sono mai stati concretizzati. Sono semplicemente per semplificare la descrizione delle modifiche.

Oltre alle considerazioni teoriche basate su protocollo, ci sono pratiche a causa dell'esistenza di librerie client che coinvolgono e codice scritto a mano. Ove possibile, testa le modifiche che stai prendendo in considerazione generando nuove versioni delle librerie client e assicurandoti che i relativi test continuino a superare.

La discussione riportata di seguito suddivide i messaggi proto in tre categorie:

  • Messaggi di richiesta (ad esempio GetBookRequest)
  • Messaggi di risposta (ad esempio ListBooksResponse)
  • Messaggi di risorse (ad esempio Book, inclusi eventuali messaggi utilizzati all'interno di altri messaggi di risorse)

Queste categorie hanno regole diverse perché i messaggi di richiesta vengono inviati solo dal client al server, i messaggi di risposta vengono inviati solo il server al client, ma in genere i messaggi delle risorse vengono inviati in entrambi i modi. In particolare, le risorse che possono essere aggiornate devono essere considerate in termini di un ciclo di lettura/modifica/scrittura.

Modifiche compatibili con le versioni precedenti

Aggiunta di un'interfaccia API a una definizione di servizio API

Dal punto di vista del protocollo, è sempre sicuro. L'unico avviso è che il cliente le librerie potrebbero aver già utilizzato il nuovo nome dell'interfaccia API le API nel tuo codice. Se la tua nuova interfaccia è completamente ortogonale a quelle esistenti, improbabile; se si tratta di una versione semplificata di un'interfaccia esistente, allora che potrebbero causare un conflitto.

Aggiunta di un metodo a un'interfaccia API

A meno che tu non aggiunga un metodo in conflitto con un metodo già in uso generati nelle librerie client, non è un problema.

ad esempio perché potrebbe non funzionare: se hai un metodo GetFoo, la riga C# generatore di codice creerà già metodi GetFoo e GetFooAsync. Aggiunta in corso... un metodo GetFooAsync nell'interfaccia API sarebbe quindi un'interruzione modifiche dal punto di vista della libreria client.)

Aggiunta di un'associazione HTTP a un metodo

Presumendo che l'associazione non presenti ambiguità, il server rispondere a un URL che in precedenza avrebbe rifiutato è sicuro. Questo potrebbe essere quando si esegue un'operazione esistente, viene applicata a un nuovo pattern del nome della risorsa.

Aggiunta di un campo a un messaggio di richiesta

L'aggiunta di campi di richiesta può essere completa, a patto che i client che non specificare che il campo verrà trattato nello stesso modo nella nuova versione e nella vecchia completamente gestita.

L'esempio più ovvio di questa situazione è il caso in cui impaginazione: se la versione 1.0 dell'API non include l'impaginazione per una raccolta, non può essere aggiunto nella versione 1.1 a meno che il valore predefinito page_size non venga considerato infinito (che in genere è una cattiva idea). In caso contrario, i clienti della versione 1.0 che si aspettano di ricevere i risultati completi di una singola richiesta potrebbero ricevere risultati troncati, senza consapevolezza che la raccolta contiene più risorse.

Aggiungere un campo a un messaggio di risposta

Un messaggio di risposta che non è una risorsa (ad es. un ListBooksResponse) può essere espanso senza interrompere i client, a condizione che ciò non modifichi il comportamento di altri campi di risposta. Qualsiasi campo precedentemente compilato in una risposta dovrebbe continuare a essere compilata con la stessa semantica, anche se questo introduce ridondanza.

Ad esempio, una risposta a una query in 1.0 potrebbe avere un campo booleano contained_duplicates per indicare che alcuni risultati sono stati omessi a causa di duplicati. Nella sezione 1.1, potremmo fornire informazioni più dettagliate in una Campo duplicate_count. Anche se è ridondante dal punto di vista 1.1, Il campo contained_duplicates deve essere ancora compilato.

Aggiunta di un valore a un enum

Un'enumerazione utilizzata solo in un messaggio di richiesta può essere liberamente espansa in includere nuovi elementi. Ad esempio, utilizzando Pattern Visualizzazione risorse, una nuova vista può essere aggiunto in una nuova versione secondaria. I clienti non hanno mai bisogno di ricevere questo numero enum, non devono necessariamente essere consapevoli di valori che non gli interessano.

Per i messaggi di risorse e i messaggi di risposta, il presupposto predefinito è che I clienti dovrebbero gestire valori enum di cui non sono a conoscenza di. Tuttavia, i produttori di API devono essere consapevoli che la scrittura di applicazioni per gestire correttamente i nuovi elementi dell'enum può essere difficile. I proprietari delle API dovrebbero documentare il comportamento previsto del client quando rileva un valore enum sconosciuto.

Proto3 consente ai clienti di ricevere un valore di cui non sono a conoscenza e di eseguire di nuovo la mantenendo lo stesso valore, in modo da non interrompere le operazioni di lettura/modifica/scrittura ciclo di lancio di Android. Il formato JSON consente di inviare un valore numerico dove il valore "name" della il valore è sconosciuto, ma il server di solito non sa se un cliente conosce un certo valore. Di conseguenza, i client JSON consapevoli di avere ricevuto un valore che prima non conoscevano, ma vedranno solo il nome o il numero e non sapranno entrambi. La restituzione dello stesso valore al server in un ciclo di lettura/modifica/scrittura deve non modificare quel campo, in quanto il server deve comprendere entrambi i moduli.

Aggiunta di un campo di risorsa solo di output

I campi di un'entità risorsa forniti solo dal server possono essere aggiunto. Il server può confermare che qualsiasi valore fornito dal client in una richiesta è valida, ma non deve avere esito negativo se il valore viene omesso.

Modifiche non compatibili con le versioni precedenti

Rimozione o ridenominazione di un servizio, un campo, un metodo o un valore enum

Fondamentalmente, se il codice client può fare riferimento a qualcosa, la rimozione o la ridenominazione è una modifica che comporta un interruzione e deve comportare un aumento della versione principale. Il codice che fa riferimento al vecchio nome causerà errori in fase di compilazione per alcuni linguaggi (come C# e Java) e potrebbero causare errori in fase di esecuzione o la perdita di dati in altre lingue. La compatibilità del formato del cavo in questo caso non è pertinente.

Modificare un'associazione HTTP

"Cambia" "delete and add" (elimina e aggiungi). Ad esempio, se decidi che vuoi supportare PATCH, ma la tua versione pubblicata supporta PUT, non hai utilizzato il nome del verbo personalizzato sbagliato, puoi aggiungere la nuova associazione, non deve rimuovere l'associazione precedente per gli stessi motivi della rimozione di un è una modifica che provoca un errore.

Modificare il tipo di un campo

Anche se il nuovo tipo è compatibile con il formato filo, il generato dal codice per le librerie client e pertanto deve comportare un aumento l'aumento delle versioni. Per linguaggi compilati e digitati in modo statico questo può introdurre facilmente errori di tempo di compilazione.

Modifica del formato di un nome di risorsa

Il nome di una risorsa non deve essere modificato, il che significa che i nomi delle raccolte non possono essere modificati.

A differenza della maggior parte delle modifiche che provocano un errore, ciò interessa anche le versioni principali: se un client puoi aspettarti di utilizzare la versione 2.0 per accedere a una risorsa creata nella versione 1.0 o viceversa, utilizzare lo stesso nome risorsa in entrambe le versioni.

In modo più discreto, nemmeno l'insieme di nomi di risorse valide deve cambiare, ad esempio per i seguenti motivi:

  • Se diventa più restrittiva, una richiesta che in precedenza avrebbe riuscito ora non riuscirà.
  • Se diventa meno restrittiva di quanto documentato in precedenza, i client che fanno ipotesi in base alla documentazione precedente potrebbero non funzionare. I clienti hanno molto probabilmente la tendenza a memorizzare i nomi delle risorse altrove, in modi che potrebbero essere sensibili all'insieme di caratteri consentiti e alla lunghezza del nome. In alternativa, i clienti potrebbero eseguire la convalida del proprio nome risorsa la documentazione. Ad esempio, Amazon ha avvisato i clienti e ha dovuto effettuare la migrazione punto quando hanno iniziato a consentire ID risorsa EC2 più lunghi.)

Tieni presente che una modifica di questo tipo potrebbe essere visibile solo nella documentazione di un protocollo. Pertanto, quando si esamina un CL per rilevare eventuali malfunzionamenti, non è sufficiente rivedere modifiche che non riguardano i commenti.

Modifica del comportamento visibile delle richieste esistenti

I client dipenderanno spesso dal comportamento dell'API e dalla semantica, anche quando non è esplicitamente supportato né documentato. Pertanto, nella maggior parte dei casi, la modifica del comportamento o della semantica dei dati dell'API verrà considerata come i consumatori. Se il comportamento non è crittograficamente nascosto, dovresti presumere che gli utenti l'abbiano scoperta e che dipende da quest'ultima.

Per questo motivo, è consigliabile anche criptare i token di paginazione (anche se i dati non sono interessanti), per impedire agli utenti di creare i propri token e potenzialmente danneggiarli quando il comportamento dei token cambia.

Modifica del formato dell'URL nella definizione HTTP

Ci sono due tipi di modifiche da considerare in questo caso, oltre alle modifiche al nome della risorsa sopra elencati:

  • Nomi dei metodi personalizzati: anche se non fanno parte del nome della risorsa, un metodo personalizzato fa parte dell'URL pubblicato dai client REST. La modifica del nome di un metodo personalizzato non dovrebbe interrompere i client gRPC, ma le API pubbliche devono presupporre di avere client REST.
  • Nomi dei parametri della risorsa: una modifica da v1/shelves/{shelf}/books/{book} a v1/shelves/{shelf_id}/books/{book_id} non influisce sulla sostituzione del nome della risorsa, ma ciò potrebbe influire sulla generazione del codice.

Aggiunta di un campo di lettura/scrittura a un messaggio della risorsa

I client eseguono spesso operazioni di lettura/modifica/scrittura. La maggior parte dei clienti non fornire valori per i campi di cui non sono a conoscenza, e proto3 in particolare non supportano questa funzionalità. Puoi specificare che eventuali campi mancanti nei tipi di messaggi (anziché i tipi primitivi) significa che a questi campi non viene applicato un aggiornamento, ma Ciò rende più difficile rimuovere esplicitamente un valore di questo campo da un'entità. I tipi primitivi (inclusi string e bytes) non possono essere gestiti in questo modo, poiché non c'è differenza in proto3 tra specificare esplicitamente int32 su 0 senza specificarlo.

Se tutti gli aggiornamenti vengono eseguiti utilizzando una maschera di campo, non è un problema perché Il client non sovrascrive in modo implicito i campi di cui non è a conoscenza. Tuttavia, una decisione insolita relativa alle API: la maggior parte delle API consente "intera risorsa" aggiornamenti.