gRPC vs. REST: Erste Schritte mit dem besten API-Protokoll
Veröffentlicht: 2022-07-22In der heutigen Technologielandschaft erfordern die meisten Projekte die Verwendung von APIs. APIs überbrücken die Kommunikation zwischen Diensten, die ein einzelnes, komplexes System darstellen, sich aber auch auf separaten Computern befinden oder mehrere, inkompatible Netzwerke oder Sprachen verwenden können.
Viele Standardtechnologien adressieren die dienstübergreifenden Kommunikationsanforderungen verteilter Systeme, wie REST, SOAP, GraphQL oder gRPC. Während REST ein bevorzugter Ansatz ist, ist gRPC ein würdiger Anwärter, der hohe Leistung, getippte Verträge und hervorragende Tools bietet.
REST-Übersicht
Representational State Transfer (REST) ist ein Mittel zum Abrufen oder Bearbeiten der Daten eines Dienstes. Eine REST-API ist im Allgemeinen auf dem HTTP-Protokoll aufgebaut und verwendet einen URI, um eine Ressource auszuwählen, und ein HTTP-Verb (z. B. GET, PUT, POST), um die gewünschte Operation auszuwählen. Anforderungs- und Antworttextkörper enthalten Daten, die für den Vorgang spezifisch sind, während ihre Header Metadaten bereitstellen. Sehen wir uns zur Veranschaulichung ein vereinfachtes Beispiel zum Abrufen eines Produkts über eine REST-API an.
Hier fordern wir eine Produktressource mit der ID 11
an und weisen die API an, im JSON-Format zu antworten:
GET /products/11 HTTP/1.1 Accept: application/json
Angesichts dieser Anfrage könnte unsere Antwort (irrelevante Header weggelassen) wie folgt aussehen:
HTTP/1.1 200 OK Content-Type: application/json { id: 11, name: "Purple Bowtie", sku: "purbow", price: { amount: 100, currencyCode: "USD" } }
Obwohl JSON für Menschen lesbar sein kann, ist es nicht optimal, wenn es zwischen Diensten verwendet wird. Die sich wiederholende Natur des Verweisens auf Eigenschaftsnamen – selbst wenn sie komprimiert sind – kann zu aufgeblähten Nachrichten führen. Sehen wir uns eine Alternative an, um dieses Problem anzugehen.
gRPC-Übersicht
gRPC Remote Procedure Call (gRPC) ist ein Open-Source-, vertragsbasiertes, plattformübergreifendes Kommunikationsprotokoll, das die Kommunikation zwischen Diensten vereinfacht und verwaltet, indem es eine Reihe von Funktionen für externe Clients verfügbar macht.
gRPC baut auf HTTP/2 auf und nutzt Funktionen wie bidirektionales Streaming und integrierte Transport Layer Security (TLS). gRPC ermöglicht eine effizientere Kommunikation durch serialisierte binäre Nutzlasten. Es verwendet standardmäßig Protokollpuffer als Mechanismus für die Serialisierung strukturierter Daten, ähnlich wie die Verwendung von JSON durch REST.
Im Gegensatz zu JSON sind Protokollpuffer jedoch mehr als ein serialisiertes Format. Sie umfassen drei weitere Hauptteile:
- Eine Vertragsdefinitionssprache, die in
.proto
Dateien zu finden ist (Wir folgen proto3, der neuesten Spezifikation der Protokollpuffersprache.) - Generierter Accessor-Funktionscode
- Sprachspezifische Laufzeitbibliotheken
Die Remote-Funktionen, die für einen Dienst verfügbar sind (definiert in einer .proto
-Datei), sind innerhalb des Dienstknotens in der Protokollpufferdatei aufgelistet. Als Entwickler können wir diese Funktionen und ihre Parameter mithilfe des reichhaltigen Typsystems von Protokollpuffern definieren. Dieses System unterstützt verschiedene numerische und Datumstypen, Listen, Wörterbücher und Nullables, um unsere Eingabe- und Ausgabenachrichten zu definieren.
Diese Dienstdefinitionen müssen sowohl dem Server als auch dem Client zur Verfügung stehen. Leider gibt es keinen Standardmechanismus, um diese Definitionen gemeinsam zu nutzen, abgesehen vom direkten Zugriff auf die .proto
-Datei selbst.
Diese .proto
-Beispieldatei definiert eine Funktion zum Zurückgeben eines Produkteintrags bei gegebener ID:
Die strenge Typisierung und Feldreihenfolge von proto3 machen die Deserialisierung von Nachrichten erheblich weniger anstrengend als das Parsen von JSON.
Vergleich von REST und gRPC
Zusammenfassend sind die wichtigsten Punkte beim Vergleich von REST vs. gRPC:
SICH AUSRUHEN | gRPC | |
---|---|---|
Plattformübergreifend | Ja | Ja |
Nachrichtenformat | Benutzerdefiniert, aber im Allgemeinen JSON oder XML | Protokollpuffer |
Größe der Nachrichtennutzlast | Mittelgroß | Klein |
Verarbeitungskomplexität | Höher (Textanalyse) | Lower (wohldefinierte binäre Struktur) |
Browser-Unterstützung | Ja (einheimisch) | Ja (über gRPC-Web) |
Wo weniger strenge Verträge und häufige Ergänzungen der Nutzlast erwartet werden, passen JSON und REST hervorragend. Wenn Verträge eher statisch bleiben und Geschwindigkeit von größter Bedeutung ist, gewinnt gRPC im Allgemeinen. In den meisten Projekten, an denen ich gearbeitet habe, hat sich gRPC als leichter und performanter als REST erwiesen.
gRPC-Dienstimplementierung
Lassen Sie uns ein optimiertes Projekt erstellen, um zu untersuchen, wie einfach es ist, gRPC einzuführen.
Erstellen des API-Projekts
Zunächst erstellen wir ein .NET 6-Projekt in Visual Studio 2022 Community Edition (VS). Wir wählen die ASP.NET Core gRPC-Dienstvorlage aus und benennen sowohl das Projekt (wir verwenden InventoryAPI
) als auch unsere erste Lösung darin ( Inventory
) .
Wählen wir nun die . NET 6.0 (Langzeitunterstützung) Option für unser Framework:
Definition unseres Produktservices
Nachdem wir das Projekt erstellt haben, zeigt VS einen beispielhaften gRPC-Prototyp-Definitionsdienst namens Greeter
an. Wir werden die Kerndateien von Greeter
an unsere Bedürfnisse anpassen.
- Um unseren Vertrag zu erstellen, ersetzen wir den Inhalt von
greet.proto
durch Snippet 1 und benennen die Dateiproduct.proto
. - Um unseren Dienst zu erstellen, ersetzen wir den Inhalt der Datei
GreeterService.cs
durch Snippet 2 und benennen die DateiProductCatalogService.cs
um.
Der Dienst gibt jetzt ein hartcodiertes Produkt zurück. Damit der Dienst funktioniert, müssen wir nur die Dienstregistrierung in Program.cs
ändern, um auf den neuen Dienstnamen zu verweisen. In unserem Fall benennen wir app.MapGrpcService<GreeterService>();
zu app.MapGrpcService<ProductCatalogService>();
um unsere neue API lauffähig zu machen.
Faire Warnung: Nicht Ihr Standardprotokolltest
Auch wenn wir versucht sind, es zu versuchen, können wir unseren gRPC-Dienst nicht über einen Browser testen, der auf seinen Endpunkt ausgerichtet ist. Wenn wir dies versuchen würden, würden wir eine Fehlermeldung erhalten, die darauf hinweist, dass die Kommunikation mit gRPC-Endpunkten über einen gRPC-Client erfolgen muss.
Client erstellen
Um unseren Dienst zu testen, verwenden wir die grundlegende Konsolen-App-Vorlage von VS und erstellen einen gRPC-Client zum Aufrufen der API. Ich habe meine InventoryApp
genannt.
Lassen Sie uns der Einfachheit halber auf einen relativen Dateipfad verweisen, über den wir unseren Vertrag teilen. Wir fügen den Verweis manuell zur .csproj
-Datei hinzu. Dann aktualisieren wir den Pfad und stellen den Client
-Modus ein. Hinweis: Ich empfehle Ihnen, sich mit Ihrer lokalen Ordnerstruktur vertraut zu machen und Vertrauen in sie zu haben, bevor Sie relative Verweise verwenden.
Hier sind die .proto
Referenzen, wie sie sowohl in den Dienst- als auch in den Client-Projektdateien erscheinen:
Dienstprojektdatei (Code zum Kopieren in die Client-Projektdatei) | Client-Projektdatei (Nach dem Einfügen und Bearbeiten) |
---|---|
|
|
Um unseren Service aufzurufen, ersetzen wir jetzt den Inhalt von Program.cs
. Unser Kodex wird eine Reihe von Zielen erreichen:
- Erstellen Sie einen Kanal, der den Standort des Dienstendpunkts darstellt (der Port kann variieren, konsultieren Sie daher die Datei
launchsettings.json
“ für den tatsächlichen Wert). - Erstellen Sie das Client-Objekt.
- Erstellen Sie eine einfache Anfrage.
- Senden Sie die Anfrage.
Vorbereitung für den Start
Um unseren Code zu testen, klicken wir in VS mit der rechten Maustaste auf die Lösung und wählen Set Startup Projects . Im Dialogfeld Lösungseigenschaftenseiten werden wir:
- Wählen Sie das Optionsfeld neben Multiple startup projects aus und setzen Sie im Dropdown-Menü Action beide Projekte (
InventoryAPI
undInventoryApp
) auf Start . - Klicken Sie auf OK .
Jetzt können wir die Lösung starten, indem wir in der VS-Symbolleiste auf Start klicken (oder die Taste F5 drücken). Zwei neue Konsolenfenster werden angezeigt: eines, um uns mitzuteilen, dass der Dienst zuhört, das andere, um uns Details des abgerufenen Produkts anzuzeigen.
gRPC-Vertragsfreigabe
Lassen Sie uns nun eine andere Methode verwenden, um den gRPC-Client mit der Definition unseres Dienstes zu verbinden. Die für Kunden zugänglichste Lösung zur Vertragsteilung besteht darin, unsere Definitionen über eine URL verfügbar zu machen. Andere Optionen sind entweder sehr spröde (Datei wird über einen Pfad geteilt) oder erfordern mehr Aufwand (Vertrag wird über ein natives Paket geteilt). Die gemeinsame Nutzung über eine URL (wie es SOAP und Swagger/OpenAPI tun) ist flexibel und erfordert weniger Code.
Stellen Sie zunächst die .proto
-Datei als statischen Inhalt zur Verfügung. Wir werden unseren Code manuell aktualisieren, da die Benutzeroberfläche der Build-Aktion auf „Protobuf Compiler“ eingestellt ist. Diese Änderung weist den Compiler an, die .proto
-Datei zu kopieren, damit sie von einer Webadresse bereitgestellt werden kann. Wenn diese Einstellung über die VS-Benutzeroberfläche geändert würde, würde der Build abbrechen. Unser erster Schritt besteht also darin, Snippet 4 zur Datei InventoryAPI.csproj
hinzuzufügen:
Als Nächstes fügen wir den Code in Snippet 5 oben in der Datei ProductCatalogService.cs
ein, um einen Endpunkt einzurichten, der unsere .proto
-Datei zurückgibt:
Und jetzt fügen wir Snippet 6 direkt vor app.Run()
, ebenfalls in der Datei ProductCatalogService.cs
:
Mit den hinzugefügten Snippets 4-6 sollte der Inhalt der .proto
-Datei im Browser sichtbar sein.
Ein neuer Testclient
Jetzt wollen wir einen neuen Konsolenclient erstellen, den wir mit dem Abhängigkeitsassistenten von VS mit unserem vorhandenen Server verbinden. Das Problem ist, dass dieser Assistent kein HTTP/2 spricht. Daher müssen wir unseren Server so einstellen, dass er über HTTP/1 spricht, und den Server starten. Da unser Server jetzt seine .proto
-Datei zur Verfügung stellt, können wir einen neuen Testclient erstellen, der sich über den gRPC-Assistenten in unseren Server einklinkt.
- Um unseren Server so zu ändern, dass er über HTTP/1 kommuniziert, bearbeiten wir unsere JSON-Datei
appsettings.json
:- Passen Sie das Feld
Protocol
(im PfadKestrel.EndpointDefaults.Protocols
) so an, dass esHttps
liest. - Speicher die Datei.
- Passen Sie das Feld
- Damit unser neuer Client diese
proto
-Informationen lesen kann, muss der Server laufen. Ursprünglich haben wir sowohl den vorherigen Client als auch unseren Server aus dem VS-Dialog Set Startup Projects gestartet. Passen Sie die Serverlösung so an, dass nur das Serverprojekt gestartet wird, und starten Sie dann die Lösung. (Nachdem wir die HTTP-Version geändert haben, kann unser alter Client nicht mehr mit dem Server kommunizieren.) - Erstellen Sie als Nächstes den neuen Testclient. Starten Sie eine weitere Instanz von VS. Wir wiederholen die im Abschnitt „Erstellen des API-Projekts “ beschriebenen Schritte, aber dieses Mal wählen wir die Konsolen-App- Vorlage. Wir nennen unser Projekt und unsere Lösung
InventoryAppConnected
. - Nachdem das Clientgehäuse erstellt wurde, stellen wir eine Verbindung zu unserem gRPC-Server her. Erweitern Sie das neue Projekt im VS Solution Explorer.
- Klicken Sie mit der rechten Maustaste auf Abhängigkeiten und wählen Sie im Kontextmenü Verbundene Dienste verwalten aus.
- Klicken Sie auf der Registerkarte Verbundene Dienste auf Dienstverweis hinzufügen und wählen Sie gRPC aus.
- Wählen Sie im Dialogfeld Dienstverweis hinzufügen die Option URL und geben Sie die
http
-Version der Dienstadresse ein (denken Sie daran, die zufällig generierte Portnummer auslaunchsettings.json
) . - Klicken Sie auf Fertig stellen , um eine Servicereferenz hinzuzufügen, die einfach verwaltet werden kann.
Fühlen Sie sich frei, Ihre Arbeit anhand des Beispielcodes für dieses Beispiel zu überprüfen. Da VS unter der Haube denselben Client generiert hat, den wir in unserer ersten Testrunde verwendet haben, können wir den Inhalt der Datei „ Program.cs
“ aus dem vorherigen Dienst wörtlich wiederverwenden.
Wenn wir einen Vertrag ändern, müssen wir unsere Client-gRPC-Definition ändern, damit sie mit der aktualisierten .proto
Definition übereinstimmt. Dazu müssen wir lediglich auf die Connected Services von VS zugreifen und den entsprechenden Serviceeintrag aktualisieren. Jetzt ist unser gRPC-Projekt abgeschlossen und es ist einfach, unseren Dienst und Client synchron zu halten.
Ihr nächster Projektkandidat: gRPC
Unsere gRPC-Implementierung bietet einen Einblick aus erster Hand in die Vorteile der Verwendung von gRPC. REST und gRPC haben je nach Vertragstyp jeweils ihre eigenen idealen Anwendungsfälle. Wenn jedoch beide Optionen passen, empfehle ich Ihnen, gRPC auszuprobieren – damit sind Sie in der Zukunft der APIs einen Schritt voraus.