Compatibilità

Mantieni tutto organizzato con le raccolte Salva e classifica i contenuti in base alle tue preferenze.

In questa pagina vengono fornite spiegazioni più dettagliate sull'elenco delle modifiche che provocano errori e non provocano errori, indicate nella sezione Controllo delle versioni.

Non è sempre chiaro che cosa viene considerato una modifica che provoca un errore (non è compatibile). Le indicazioni in questa sezione devono essere trattate come indicative anziché un elenco completo di ogni possibile modifica.

Le regole elencate qui riguardano solo la compatibilità del client. Si prevede che i produttori delle API siano a conoscenza dei propri requisiti relativi al deployment, incluse le modifiche ai dettagli dell'implementazione.

In genere, i client non devono interrompere il funzionamento di un servizio che esegue l'aggiornamento a una nuova versione secondaria o a una patch. I tipi di interruzioni che vengono presi in considerazione sono:

  • Compatibilità della sorgente: codice scritto contro la versione 1.0 non compilato in base a 1.1
  • Compatibilità binaria: codice compilato in base a 1,0 in quanto non consente il collegamento o l'esecuzione in base a una libreria client 1.1. I dettagli esatti dipendono dalla piattaforma client, ma esistono diverse varianti in situazioni diverse.
  • Compatibilità dei cavi: un'applicazione creata contro una versione 1.0 non comunicata con un server 1.1.
  • Compatibilità semantica: tutto viene eseguito, ma genera risultati 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, se vogliono eseguire l'aggiornamento a una nuova versione secondaria (ad esempio per sfruttare una nuova funzionalità), dovrebbero essere in grado di farlo facilmente.

Nota: per quanto riguarda i numeri di versione, come v1.1 e v1.0, si fa riferimento a numeri di versione logici che non sono mai stati concreti. ma sono utilizzati solo per semplificare la descrizione delle modifiche.

Oltre a considerazioni teoriche basate su protocollo, esistono considerazioni pratiche dovute all'esistenza di librerie client che coinvolgono sia il codice generato sia il codice scritto a mano. Dove possibile, prova le modifiche che stai valutando di generare nuove versioni delle librerie client e di assicurarti che i loro test continuino a essere superati.

La seguente discussione suddivide i messaggi protocollo in tre categorie:

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

Queste categorie hanno regole diverse, poiché i messaggi di richiesta vengono inviati sempre dal client al server, i messaggi di risposta vengono inviati solo dal 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 ciclo di lettura/modifica/scrittura.

Modifiche compatibili con le versioni precedenti (senza interruzioni)

Aggiungere un'interfaccia API a una definizione di servizio API

Dal punto di vista del protocollo, questo è sempre sicuro. L'unica precisazione è che le librerie client potrebbero aver già utilizzato il nuovo nome dell'interfaccia API all'interno del codice scritto a mano. Se la nuova interfaccia è completamente ortogonale a quella esistente, questo è improbabile. Se è una versione semplificata di un'interfaccia esistente, è molto probabile che si verifichi un conflitto.

Aggiunta di un metodo a un'interfaccia API

Se non aggiungi un metodo in conflitto con un metodo già generato nelle librerie client, non è un problema.

Ad esempio, se si verifica un errore: se hai un metodo GetFoo, il generatore di codice C# creerà già i metodi GetFoo e GetFooAsync. Pertanto, l'aggiunta di un metodo GetFooAsync nell'interfaccia API sarebbe una modifica che provoca un errore dal punto di vista della libreria client.

Aggiunta di un'associazione HTTP a un metodo

Supponendo che l'associazione non introduca ambiguità, rendere sicuro il server a un URL che in precedenza avrebbe rifiutato. Questa operazione può essere eseguita quando si applica un'operazione esistente a un nuovo pattern del nome della risorsa.

Aggiungere un campo a un messaggio di richiesta

L'aggiunta di campi di richiesta può essere ininterrotta, a condizione che i client che non specificano il campo verranno trattati nella stessa versione e nella versione precedente.

L'esempio più ovvio di dove può essere fatto in modo errato è con l'impaginazione: se la versione v1.0 dell'API non include l'impaginazione per una raccolta, non può essere aggiunta in v1.1 a meno che l'opzione page_size non venga considerata come infinita (che in genere è una cattiva idea). In caso contrario, i client v1.0 che si aspettano di ottenere risultati completi da un'unica richiesta potrebbero ricevere risultati troncati, senza consapevolezza che la raccolta contenga più risorse.

Aggiungere un campo a un messaggio di risposta

Un messaggio di risposta diverso da una risorsa (ad esempio, ListBooksResponse) può essere espanso senza danneggiare i client, a condizione che il comportamento degli altri campi di risposta non venga modificato. I campi inseriti in precedenza in una risposta devono continuare a essere compilati con la stessa semantica, anche se ciò rappresenta una ridondanza.

Ad esempio, una risposta alla query in 1.0 potrebbe avere un campo booleano contained_duplicates per indicare che alcuni risultati sono stati omessi a causa della duplicazione. In 1.1, potremmo fornire informazioni più dettagliate in un campo duplicate_count. Anche se ridondante da una prospettiva 1.1, il campo contained_duplicates deve ancora essere compilato.

Aggiunta di un valore a un'enumerazione

L'enumerazione utilizzata solo in un messaggio di richiesta può essere espansa in modo da includere nuovi elementi. Ad esempio, utilizzando il pattern Vista risorse è possibile aggiungere una nuova vista in una nuova versione secondaria. I clienti non hanno bisogno di ricevere questa enumerazione, perciò non devono essere a conoscenza dei valori a cui non sono interessati.

Per i messaggi di risorse e di risposta, l'ipotesi predefinita è che i client dovrebbero gestire valori enumerati di cui non sono a conoscenza. Tuttavia, i produttori di API devono essere consapevoli che scrivere applicazioni per gestire correttamente nuovi elementi di enumerazione potrebbe essere difficile. I proprietari delle API devono documentare il comportamento previsto del client quando si verifica un valore di enumerazione sconosciuto.

Proto3 consente ai client di ricevere un valore di cui non sono a conoscenza e di apprezzare il messaggio mantenendo lo stesso valore, in modo da non interrompere il ciclo di lettura/modifica/scrittura. Il formato JSON consente l'invio di un valore numerico ove ""name" per il valore è sconosciuto, ma il server solitamente non saprà se il client è a conoscenza o meno di un determinato valore. I client JSON potrebbero quindi essere consapevoli di aver ricevuto un valore in precedenza sconosciuto, ma potranno visualizzare solo il nome o il numero (non conosceranno entrambi). Restituire lo stesso valore al server in un ciclo di lettura/modifica/scrittura non deve modificare il campo, poiché il server deve comprendere entrambi i moduli.

Aggiunta di un campo delle risorse di solo output

Possono essere aggiunti i campi di un'entità di risorse forniti solo dal server . Il server potrebbe convalidare che un valore fornito dal client in una richiesta sia valido, ma non deve avere esito negativo se il valore viene omesso.

Modifiche incompatibili con le versioni precedenti (breaking)

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

In pratica, se il codice client potrebbe fare riferimento a qualcosa, rimuoverla o rinominarla è una modifica che provoca un errore e deve determinare un aumento significativo della versione. Il codice che fa riferimento al vecchio nome causerà errori al momento della compilazione per alcuni linguaggi (ad esempio C# e Java) e potrebbe causare errori nei tempi di esecuzione o perdita di dati in altri linguaggi. La compatibilità con il formato del cavo non è rilevante qui.

Modificare un'associazione HTTP

"Cambia" qui è efficace "elimina e aggiungi". Ad esempio, se decidi di supportare davvero PATCH, ma la tua versione pubblicata supporta PUT, o se hai utilizzato il nome verbo personalizzato errato, puoi aggiungere la nuova associazione, ma non devi rimuovere la precedente associazione per gli stessi motivi della rimozione di un metodo di servizio.

Modificare il tipo di un campo

Anche se il nuovo tipo è compatibile con il formato cablato, questo potrebbe modificare il codice generato per le librerie client e, di conseguenza, deve determinare un aumento significativo della versione. Per i linguaggi compilati e di tipo statico, questo può facilmente introdurre errori durante la compilazione.

Modifica del formato di un nome della risorsa

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

A differenza della maggior parte delle modifiche che provocano errori, questa azione influisce anche sulle versioni principali: se un client può utilizzare la versione 2.0 per accedere a una risorsa creata in v1.0 o viceversa, deve essere utilizzato lo stesso nome risorsa in entrambe le versioni.

Più lievemente, anche l'insieme di nomi di risorse validi non deve cambiare, per i motivi seguenti:

  • Se diventa più restrittiva, una richiesta che in precedenza avrebbe avuto esito positivo ora avrà esito negativo.
  • Se diventa meno restrittivo di quanto documentato in precedenza, i clienti che effettuano ipotesi sulla base della documentazione precedente potrebbero presentare errori. I client hanno maggiori probabilità di archiviare i nomi delle risorse altrove, in modi che potrebbero essere sensibili al set di caratteri consentiti e alla lunghezza del nome. In alternativa, i client potrebbero eseguire la convalida del proprio nome della risorsa per seguire la documentazione. Ad esempio, Amazon ha offerto ai clienti un grande preavviso e ha avuto un periodo di migrazione, quando hanno iniziato a consentire ID risorsa EC2 più lunghi.

Tieni presente che tale modifica potrebbe essere visibile solo nella documentazione di un protocollo. Pertanto, quando esamini un elenco modifiche in caso di interruzione, non è sufficiente esaminare le modifiche non relative ai commenti.

Modifica del comportamento visibile delle richieste esistenti

I client dipendono spesso dal comportamento dell'API e dalla semantica, anche quando tale comportamento non è esplicitamente supportato o documentato. Pertanto, nella maggior parte dei casi la modifica del comportamento o della semantica dei dati dell'API verrà considerata un'interruzione da parte dei consumatori. Se questo comportamento non è nascosto in modo crittografico, devi presumere che gli utenti l'abbiano scoperto e che dipendono da questo.

Potrebbe essere una buona idea criptare i token di impaginazione per questo motivo (anche quando i dati non sono interessanti) per evitare che gli utenti creino i propri token e possano potenzialmente non funzionare quando il comportamento dei token cambia.

Modificare il formato URL nella definizione HTTP

Ci sono due tipi di modifiche da considerare in aggiunta alle modifiche dei nomi delle risorse elencate sopra:

  • Nomi dei metodi personalizzati: sebbene non siano parte del nome della risorsa, il nome del metodo personalizzato fa parte dell'URL pubblicato dai client REST. La modifica del nome di un metodo personalizzato non deve interrompere i client gRPC, ma le API pubbliche devono supporre che dispongano di client REST.
  • Nomi dei parametri delle risorse: una modifica da v1/shelves/{shelf}/books/{book} a v1/shelves/{shelf_id}/books/{book_id} non influisce sul nome della risorsa sostituita, ma potrebbe influire sulla generazione del codice.

Aggiungere un campo di lettura/scrittura a un messaggio di risorse

I client spesso eseguono operazioni di lettura/modifica/scrittura. La maggior parte dei client non fornisce valori per i campi di cui non è a conoscenza, pertanto proto3 in particolare non supporta questa funzionalità. Potresti specificare che qualsiasi campo mancante dei tipi di messaggio (anziché i tipi originari) indica che non viene applicato un aggiornamento a tali campi, ma rende più difficile rimuovere esplicitamente tale valore da un'entità. I tipi primitivi (inclusi string e bytes) semplicemente non possono essere gestiti in questo modo, poiché non c'è alcuna differenza in proto3 che specifica esplicitamente un campo int32 come 0 e non lo specifica affatto.

Se tutti gli aggiornamenti vengono eseguiti utilizzando una maschera del campo, questo non è un problema perché il client non sovrascrive implicitamente i campi di cui non è a conoscenza. Tuttavia, questa sarebbe una decisione insolita: le API consentono di aggiornare "tutte le risorse".