Nel testo di oggi, voglio esaminare più da vicino gRPC e REST, probabilmente due delle approcci più comunemente utilizzati per creare API al giorno d’oggi.
I will start with a short characteristic of both tools — what they are and what they can offer. Then I will compare them according to seven categories, in my opinion, most crucial for modern-day systems.
Le categorie sono le seguenti:
- Protocolli HTTP sottostanti
- Formati di dati supportati
- Dimensione dei dati
- Throughput
- Definizioni
- Facilità di adozione
- Supporto agli strumenti
Il Perché
Quando la gente sente “API”, probabilmente pensa subito a REST API. Tuttavia, REST è solo uno dei molti approcci per la costruzione di API. Non è la soluzione miracolosa per tutti i casi d’uso. Ci sono altri modi, con RPC (Richiesta di procedura remota) essendo solo uno di loro, e gRPC è probabilmente il framework più riuscito per lavorare con RPC.
Nonostante sia una tecnologia abbastanza matura ed efficiente, gRPC è ancora considerato come il nuovo arrivato. Pertanto, è meno ampiamente adottato di REST nonostante sia abbastanza utile in alcuni casi d’uso.
Il mio motivo principale per scrivere questo post di blog è quello di diffondere gRPC e evidenziare i casi d’uso in cui può brillare.
Che cos’è REST?
REST, o Representational State Transfer, è probabilmente il modo più comune di creare un’applicazione che espone qualsiasi tipo di API. Utilizza HTTP come mezzo di comunicazione sottostante. A causa di ciò, può beneficiare di tutti i vantaggi di HTTP, come il caching.
Inoltre, essendo stateless per sua natura, REST permette una facile separazione tra client e server. Il client ha solo bisogno di conoscere l’interfaccia esposta dal server per comunicare efficacemente con esso e non dipende in alcun modo dalla implementazione del server. La comunicazione tra client e server si basa su una base di richiesta e risposta, con ogni richiesta che è una classica richiesta HTTP.
REST non è un protocollo né uno strumento (in una certa misura): è un approccio architettonico per la costruzione di applicazioni. I servizi che seguono l’approccio REST sono chiamati servizi RESTFul. Come architettura, impone diverse restrizioni ai suoi utenti. In particolare:
- Comunicazione client-server
- Comunicazione senza stato
- Memorizzazione nella cache
- Interfaccia uniforme
- Sistema gerarchico
- Codice a richiesta
I due concetti cruciali di REST sono:
- Endpoint: Un URL unico (Uniform Resource Locator) che rappresenta una risorsa specifica; può essere visto come un modo per accedere a una particolare operazione o elemento dati su Internet
- Risorsa: Un particolare pezzo di dati disponibile sotto un URL specifico
Inoltre, esiste una descrizione chiamata Modello di Maturazione di Richardson, un modello che descrive il grado di “professionalità” nelle API REST. Divide le API REST in 3 livelli (o 4, a seconda che si conti il livello 0) in base all’insieme di caratteristiche che una particolare API possiede.
Una di queste caratteristiche è che l’endpoint REST dovrebbe utilizzare nomi nell’URL e metodi HTTP corretti per gestire i suoi risorse.
- Esempio: DELETE user/1 invece di GET user/deleteById/1
Per quanto riguarda i metodi HTTP e le azioni ad essi associate, è così:
- GET – Recuperare una risorsa specifica o una raccolta di risorse
- POST – Creare una nuova risorsa
- PUT – Upsert di un’intera risorsa
- PATCH – Aggiornamento parziale di una risorsa specifica
- DELETE – Rimuovere una risorsa specifica tramite id
Il modello di maturità specifica molto altro; ad esempio, un concetto chiamato HyperMedia. HyperMedia unisce insieme la presentazione dei dati e il controllo delle azioni che i client possono eseguire.
A full description of the maturity model is out of the scope of this blog — you can read more about it here.
Nota: molte cose menzionate in questa paragrafo sono più sfumate di quanto descritto qui. REST è un argomento piuttosto vasto e merita una serie intera di articoli. Tuttavia, tutto qui è in accordo con le migliori pratiche REST comunemente note.
Che cos’è gRPC?
Si tratta ancora di un’implementazione del concetto relativamente vecchio di Remote Procedure Call. Lo hanno sviluppato gli ingegneri di Google, ecco perché nel nome c’è una “g”. Probabilmente è lo strumento più moderno ed efficiente per lavorare con RPC e inoltre è un progetto incubazione CNCF.
gRPC utilizza i Protocol Buffers di Google come formato di serializzazione, mentre sfrutta HTTP/2 come mezzo di trasporto dei dati, anche se gRPC può funzionare anche con JSON come strato dati.
I blocchi fondamentali di gRPC includono:
- Metodo: Il blocco fondamentale di gRPC, ogni metodo è una chiamata di procedura remota che accetta alcuni input e restituisce output. Esegue un’operazione singola implementata ulteriormente nel linguaggio di programmazione scelto. Per ora, gRPC supporta 4 tipi di metodi:
- Unario: Modello classico di richiesta-risposta in cui il metodo accetta input e restituisce output
- Server Streaming: I metodi accettano un messaggio come input e restituiscono uno stream di messaggi come output. gRPC garantisce l’ordine dei messaggi all’interno di una singola chiamata RPC.
- Client Streaming: Il metodo accetta lo stream di messaggi come input, li elabora fino a quando non rimangono più messaggi e poi restituisce un singolo messaggio come output. Come sopra, gRPC garantisce l’ordine dei messaggi all’interno di una singola chiamata RPC.
- Streaming bidirezionale: Il metodo prende lo stream come input e restituisce lo stream come output, efficacemente utilizzando due stream di lettura e scrittura. Entrambi gli stream operano in modo indipendente e l’ordinamento dei messaggi è preservato a livello di stream.
- Servizio: Rappresenta un gruppo di metodi – ogni metodo deve avere un nome unico all’interno del servizio. I servizi descrivono anche caratteristiche come sicurezza, timeout o retry.
- Messaggio: Un oggetto che rappresenta l’input o l’output dei metodi.
Le definizioni dell’API gRPC sono scritte sotto forma di file .proto che contengono tutti e tre i blocchi fondamentali di cui sopra. Inoltre, gRPC fornisce un compilatore di protocol buffer che genera il codice client e servizio dai nostri file .proto.
Possiamo implementare i metodi lato server come preferiamo. Dobbiamo però rispettare il contratto input-output dell’API.
Lato client, c’è un oggetto chiamato client (o stub) – simile a un client HTTP. Conosce tutti i metodi dal server e si occupa semplicemente di chiamare procedure remote e restituire le loro risposte.
La Comparazione
Protocollo HTTP Sottostante
Questa è la prima categoria e probabilmente la più importante, poiché la sua influenza può anche essere visibile in altre.
In generale, REST è basato su richiesta-risposta e utilizza HTTP/1.1 come mezzo di trasporto. Dobbiamo utilizzare un protocollo diverso come WebSocket (più informazioni su di loro qui) o qualsiasi tipo di streaming o connessione più duratura.
Possiamo anche implementare un codice di tipo hacky per far apparire il REST come streaming. Inoltre, l’uso di HTTP/1.1 per REST richiede una connessione per ogni scambio richiesta-risposta. Un tale approccio può risultare problematico per richieste a lungo termine o quando abbiamo capacità di rete limitate.
Naturalmente, possiamo utilizzare HTTP/2 per costruire API simili a REST; tuttavia, non tutti i server e le librerie supportano ancora HTTP/2. Di conseguenza, potrebbero sorgere problemi in altri luoghi.
Al contrario, gRPC utilizza solo HTTP/2. Consente di inviare più coppie richiesta-risposta attraverso una singola connessione TCP. Un tale approccio può rappresentare un significativo aumento delle prestazioni per il nostro applicativo.
- Risultato: Vantaggio leggero per gRPC
Formati di dati supportati
Nel caso predefinito in cui l’API REST utilizza HTTP/1.1, allora può supportare molti formati.
REST generalmente non impone restrizioni su formato e stile dei messaggi. Essenzialmente ogni formato che può essere serializzato in testo normale è valido. Possiamo utilizzare qualsiasi formato che meglio si adatti a una determinata situazione.
Il formato più popolare per l’invio di dati negli applicativi REST è sicuramente JSON. XML è secondo a causa del grande numero di vecchi/legacy applicativi.
Tuttavia, quando si utilizza REST con HTTP/2, allora sono supportati solo i formati di scambio binari. In questo caso, possiamo utilizzare Protobuf o Avro. Naturalmente, un tale approccio può avere i suoi svantaggi, ma ne parleremo più avanti.
Nel frattempo, gRPC supporta solo due formati per lo scambio di dati:
- Protobuf — Per impostazione predefinita
- JSON — Quando hai bisogno di integrarti con un API più vecchio
Se decidi di provare con JSON, allora gRPC utilizzerà JSON come formato di codifica per i messaggi e GSON come formato dei messaggi. Inoltre, l’utilizzo di JSON richiederà un po’ più di configurazione da eseguire. Ecco la documentazione di gRPC su come farlo.
- Risultato: Vince REST, poiché supporta più formati.
Dimensione dei dati
Per impostazione predefinita, gRPC utilizza il formato di scambio dati binario, che riduce notevolmente la dimensione dei messaggi inviati attraverso la rete: ricerca afferma che è circa il 40-50% inferiore in byte — la mia esperienza da uno dei progetti precedenti dice anche il 50-70% in meno.
L’articolo sopra fornisce un confronto di dimensioni relativamente approfondito tra JSON e Protobuff. L’autore ha anche fornito uno strumento per generare JSON e file binari. Quindi puoi ri-eseguire i suoi esperimenti e confrontare i risultati.
Gli oggetti dell’articolo sono abbastanza semplici. Tuttavia, la regola generale è — più oggetti incorporati e struttura più complessa di JSON, più pesante sarà rispetto a Protobuf. Una differenza del 50% in dimensioni a favore di Protobuf è una buona linea di base.
La differenza può essere minimizzata o eliminata utilizzando il formato di scambio binario per REST. Tuttavia, non è il modo più comune né il più supportato per realizzare API RESTful, quindi potrebbero sorgere altri problemi.
- Risultato: Nel caso predefinito, vittoria per gRPC; nel caso di entrambi che utilizzano il formato dati binario, pareggio.
Throughput
Ancora una volta, nel caso di REST, tutto dipende dal protocollo HTTP sottostante e dal server.
Nel caso predefinito, REST basato su HTTP/1.1, anche il server più performante non sarà in grado di battere le prestazioni di gRPC, soprattutto quando aggiungiamo l’overhead di serializzazione e deserializzazione quando utilizziamo JSON. Anche se quando passiamo a HTTP/2 la differenza sembra diminuire.
Per quanto riguarda il throughput massimo, in entrambi i casi, HTTP è un mezzo di trasporto, quindi ha il potenziale di scalare all’infinito. Quindi tutto dipende dalle strumentazioni che stiamo utilizzando e da cosa stiamo precisamente facendo con il nostro applicativo, poiché non ci sono limiti per progettazione.
- Risultato: Nel caso predefinito, gRPC; nel caso di entrambi che utilizzano dati binari e HTTP/2, pareggio o vittoria leggera per gRPC.
Definizioni
In questa parte, descriverò come definiamo i nostri messaggi e il servizio in entrambi gli approcci.
In molti applicativi REST, dichiariamo semplicemente le nostre richieste e risposte come classi, oggetti o qualsiasi struttura supportata da un particolare linguaggio. Quindi ci affidiamo alle librerie fornite per la serializzazione e deserializzazione di JSON/XML/YAML, o di qualsiasi formato di cui abbiamo bisogno.
Inoltre, esistono sforzi in corso per creare strumenti in grado di generare codice nel linguaggio di programmazione scelto sulla base di definizioni di API REST da Swagger. Tuttavia, sembrano essere nella versione alpha, quindi potrebbero ancora presentarsi alcuni bug e problemi minori che li rendono difficili da utilizzare.
C’è poca differenza tra formati binari e non binari per applicazioni REST, poiché la regola è più o meno la stessa in entrambi i casi. Per il formato binario, definiamo semplicemente tutto in modo richiesto da un particolare formato.
Inoltre, abbiamo definito il nostro servizio REST attraverso metodi o annotazioni dal nostro libreria o framework sottostante. Lo strumento è altresì responsabile di esporlo insieme ad altre configurazioni al mondo esterno.
Nel caso di gRPC, abbiamo Protobuf come predefinito e di fatto l’unico modo di scrivere definizioni. Dobbiamo dichiarare tutto: messaggi, servizi e metodi nei file .proto, quindi la questione è piuttosto semplice.
Quindi utilizziamo lo strumento fornito da gRPC per generare il codice per noi, e dobbiamo solo implementare i nostri metodi. Dopo ciò, tutto dovrebbe funzionare come previsto.
Inoltre, Protobuf supporta l’importazione in modo che possiamo distribuire la nostra configurazione attraverso più file in modo ragionevolmente semplice.
- Risultato: Non c’è un vincitore in questo caso, solo una descrizione e un consiglio da parte mia: scegli l’approccio che più si adatta a te.
Facilità di Adozione
In questa parte, confronterò il supporto della libreria/framework per ciascun approccio nei linguaggi di programmazione moderni.
In generale, ogni linguaggio di programmazione (Java, Scala, Python) che ho incontrato nella mia breve carriera come ingegnere software ha almeno 3 principali librerie/framework per creare applicazioni simili a REST, per non parlare di un numero simile di librerie per la conversione di JSON in oggetti/classi.
Inoltre, poiché REST utilizza formati leggibili dall’uomo per impostazione predefinita, è più facile da eseguire il debug e utilizzare per i nuovi arrivati. Ciò può anche influire sulla tempestività della consegna di nuove funzionalità e aiutarti a combattere i bug che compaiono nel tuo codice.
Insomma, il supporto per applicazioni in stile REST è almeno molto buono.
In Scala, abbiamo persino uno strumento chiamato tapir — per il quale ho avuto il piacere di essere uno dei mantenitori per un po’ di tempo. Tapir ci consente di astrarre il nostro server HTTP e scrivere endpoint che funzioneranno per diversi server.
gRPC stesso fornisce una libreria client per oltre 8 linguaggi di programmazione popolari. Di solito è sufficiente poiché queste librerie contengono tutto ciò che è necessario per creare un’API gRPC. Inoltre, sono a conoscenza di librerie che forniscono astrazioni più alte per Java (tramite Spring Boot Starter) e per Scala.
Un’altra considerazione è che oggi REST è considerato uno standard mondiale e un punto di ingresso per la creazione di servizi, mentre RPC e gRPC, in particolare, sono ancora visti come una novità nonostante siano stati introdotti da un po’ di tempo.
- Risultato: REST, poiché è più ampiamente adottato e dispone di molte più librerie e framework
Supporto alle Ferramenta
Le librerie, i framework e le quote di mercato generale sono stati trattati sopra, quindi in questa parte, vorrei trattare lo strumentario intorno a entrambi i modelli. Significa strumenti per i test, test di prestazioni/stress e documentazione.
Test automatizzati/Test
Innanzitutto, nel caso di REST, gli strumenti per la creazione di test automatizzati sono integrati in diverse librerie e framework o sono strumenti separati costruiti con questo unico scopo, come REST-assured.
Nel caso di gRPC, possiamo generare uno stub e usarlo per i test. Se vogliamo essere ancora più rigorosi, possiamo utilizzare il client generato come un’applicazione separata e usarlo come base per i nostri test sul servizio reale.
Per quanto riguarda il supporto agli strumenti esterni per gRPC, ne sono consapevole:
- App Postman supporto per gRPC
- Il client HTTP di JetBrains utilizzato nei loro IDE può anche supportare gRPC con una configurazione minima
- Risultato uno: Vittoria per REST; tuttavia, la situazione sembra migliorare per gRPC.
Test di Performance
In questo caso, REST ha significativi vantaggi, poiché strumenti come JMeter o Gatling rendono il test di stress delle API REST abbastanza facile.
Purtroppo, gRPC non ha un tale supporto. Sono consapevole che le persone da Gatling hanno il plugin gRPC incluso nella versione corrente di Gatling, quindi la situazione sembra migliorare.
Tuttavia, fino ad ora, abbiamo avuto solo un plugin e libreria non ufficiale chiamato ghz. Tutti questi sono buoni; non è solo lo stesso livello di supporto di quello per REST.
- Risultato due: Vittoria per REST; tuttavia, la situazione sembra migliorare per gRPC, ancora una volta 😉
Documentazione
Nel caso della documentazione dell’API, la vittoria è ancora una volta per REST con OpenAPI e Swagger che sono ampiamente adottati nell’industria e sono lo standard de facto. Quasi tutte le librerie per REST possono esporre documentazione swagger con minimo sforzo o già integrato.
Purtroppo, gRPC non ha nulla di simile.
Tuttavia, la domanda è se gRPC abbia davvero bisogno di uno strumento del genere. gRPC è più descrittivo di REST per sua natura, quindi potrebbero non essere necessari ulteriori strumenti di documentazione.
In generale, i file .proto con la descrizione della nostra API sono più declarativi e compatti del codice responsabile della creazione del nostro codice API REST, quindi forse non c’è bisogno di ulteriore documentazione per gRPC. Lascio a te la risposta.
- Risultato tre: Vittoria per REST; tuttavia, la questione della documentazione gRPC rimane aperta.
Risultato complessivo:
A significant victory for REST
Riepilogo
La tabella dei punteggi finali è questa.

I punteggi sono equamente divisi tra entrambi i stili, con tre vittorie ciascuno e una categoria senza un vincitore chiaro.
Non esiste una soluzione miracolosa: pensa semplicemente a quali categorie potrebbero essere le più importanti per il tuo applicativo e poi scegli l’approccio che ha vinto nella maggior parte di esse — questa è almeno la mia raccomandazione.
Per quanto riguarda la mia preferenza, darei una possibilità a gRPC se posso, poiché ha funzionato abbastanza bene nel mio ultimo progetto. Potrebbe essere una scelta migliore del vecchio e semplice REST.
Se mai avessi bisogno di aiuto nella scelta tra REST e gRPC o affrontassi qualsiasi altro tipo di problema tecnico, fammelo sapere. Potrei essere in grado di aiutarti.
Grazie per il tuo tempo.