In de huidige tekst wil ik nader kijken naar gRPC en REST, waarschijnlijk twee van de meest courante aanpakken voor het maken van API’s tegenwoordig.
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.
De categorieën zijn als volgt:
- Onderliggende HTTP-protocollen
- Ondersteunde gegevensformaten
- Gegevensgrootte
- Doorvoer
- Definities
- Gemak van acceptatie
- Toolingsupport
De Reden Waarom
Wanneer mensen “API” horen, denken ze waarschijnlijk meteen aan REST API. Echter, REST is slechts één van de vele aanpakken voor het bouwen van API’s. Het is geen wondermiddeloplossing voor alle gebruiksgevallen. Er zijn andere manieren, met RPC (Remote Procedure Call) als slechts één ervan, en gRPC is waarschijnlijk het meest succesvolle framework voor het werken met RPC.
Ondanks dat het een vrij volwassen en efficiënte technologie is, wordt gRPC nog steeds gezien als de nieuwe. Daarom is het minder wijdverspreid geaccepteerd dan REST, ondanks dat het in sommige gebruiksgevallen vrij handig is.
Mijn voornaamste reden voor het schrijven van deze blogpost is om gRPC te populariseren en gebruiksgevallen aan te wijzen waar het kan opvallen.
Wat Is REST?
REST, of Representational State Transfer, is waarschijnlijk de meest voorkomende manier om een applicatie te creëren die een API van welke aard dan ook aanbiedt. Het maakt gebruik van HTTP als onderliggende communicatiemiddel. Daardoor kan het profiteren van alle voordelen van HTTP, zoals caching.
Bovendien, door zijn oorsprong stateless, maakt REST het gemakkelijk om een scheiding tussen client en server te creëren. De client hoeft alleen de door de server aangeboden interface te kennen om effectief met de server te communiceren en is in geen enkele zin afhankelijk van de serverimplementatie. Communicatie tussen client en server is gebaseerd op een aanvraag- en antwoordbasis, waarbij elke aanvraag een klassieke HTTP-aanvraag is.
REST is geen protocol of tool (tot op zekere hoogte): het is een architectonische aanpak voor het bouwen van applicaties. De diensten die de REST-aanpak volgen, worden RESTFul-diensten genoemd. Als architectuur legt het verschillende beperkingen op aan zijn gebruikers. In het bijzonder:
- Client-server communicatie
- Stateless communicatie
- Caching
- Uniforme interface
- Gelaagde systeem
- Code op aanvraag
De twee cruciale concepten van REST zijn:
- Endpoints: Een unieke URL (Uniform Resource Locator) die een specifiek middel vertegenwoordigt; kan worden gezien als een manier om een bepaalde operatie of gegevenselement op het internet te benaderen
- Resource: Een specifiek stukje data dat onder een bepaalde URL beschikbaar is
Bovendien is er een beschrijving die bekend staat als het Richardson Maturing Model — een model dat de graad van “professionaliteit” in REST APIs beschrijft. Het verdeelt REST APIs in 3 niveaus (of 4, afhankelijk of je niveau 0 meetelt) op basis van de reeks eigenschappen die een bepaalde API heeft.
Een dergelijke eigenschap is dat de REST-eindpunten gebruik maken van zelfstandige naamwoorden in de URL en de juiste HTTP-aanvraagmethoden om hun middelen te beheren.
- Voorbeeld: DELETE user/1 in plaats van GET user/deleteById/1
Wat betreft HTTP-methoden en hun gekoppelde acties, gaat het als volgt:
- GET — Haal een specifiek middel of een verzameling middelen op
- POST — Creëer een nieuw middel
- PUT — Upsert geheel middel
- PATCH — Partiële update van specifiek middel
- DELETE — Verwijder een specifiek middel op basis van id
Het volwassenheidsmodel specificeert veel meer dan dat; bijvoorbeeld een concept genaamd HyperMedia. HyperMedia verbindt de presentatie van gegevens en de controle over acties die clients kunnen uitvoeren.
A full description of the maturity model is out of the scope of this blog — you can read more about it here.
Opmerking: veel van de hier genoemde zaken zijn genuanceerder dan hier beschreven. REST is een vrij groot onderwerp en het verdient een hele reeks artikelen. Toch is alles hier in overeenstemming met alle algemeen bekende beste praktijken voor REST.
Wat is gRPC?
Dit is opnieuw een implementatie van het relatief oude concept van Remote Procedure Call. Het is ontwikkeld door mensen van Google, vandaar de “g” in de naam. Het is waarschijnlijk de meest moderne en efficiënte tool voor het werken met RPC’s en tevens een CNCF incubatie project.
gRPC maakt gebruik van Google’s Protocol Buffers als serialisatie formaat en gebruikt HTTP/2 als transport medium voor gegevens, hoewel gRPC ook kan werken met JSON als gegevenslaag.
De basiselementen van gRPC omvatten:
- Methode: Het basiselement van gRPC, elke methode is een remote procedure call die een input neemt en output retourneert. Deze voert een enkele operatie uit, geïmplementeerd in de voorkeursprogrammeertaal. Tot nu toe ondersteunt gRPC 4 types van methoden:
- Unair: Klassiek aanvraag-antwoord model waarbij de methode input neemt en output retourneert
- Server Streaming: Methoden accepteren een bericht als input en retourneren een stroom van berichten als output. gRPC garandeert de volgorde van berichten binnen een individuele RPC oproep.
- Client Streaming: De methode neemt een stroom van berichten als input, verwerkt deze totdat er geen berichten meer over zijn, en retourneert vervolgens een enkel bericht als output. Net als bovenstaand, garandeert gRPC de volgorde van berichten binnen een individuele RPC oproep.
- Bidirectionele Streaming: De methode neemt de stroom als invoer en retourneert de stroom als uitvoer, effectief gebruik makend van twee lees- en schrijfstromen. Beide streams werken onafhankelijk en de volgorde van berichten wordt op stream-niveau behouden.
- Service: Vertegenwoordigt een groep methoden – elke methode moet binnen de service een unieke naam hebben. Services beschrijven ook functies zoals beveiliging, time-outs of herhalingen.
- Bericht: Een object dat de invoer of uitvoer van methoden vertegenwoordigt.
De gRPC API-definities zijn geschreven in de vorm van .proto-bestanden die alle drie bovenstaande basiselementen bevatten. Bovendien biedt gRPC een protocol buffer-compiler die client- en servicecode genereert uit onze .proto-bestanden.
We kunnen serverzijdige methoden zo implementeren als we willen. We moeten ons echter houden aan het input-output contract van de API.
Aan de clientzijde is er een object genaamd client (of stub) – zoals een HTTP-client. Het kent alle methoden van de server en houdt zich alleen bezig met het aanroepen van externe procedures en het retourneren van hun antwoorden.
De Vergelijking
Onderliggend HTTP-protocol
Dit is de eerste categorie en waarschijnlijk de belangrijkste, aangezien zijn invloed ook zichtbaar kan zijn in anderen.
Over het algemeen is REST aanvraag-respons gebaseerd en gebruikt het HTTP/1.1 als transportmiddel. We moeten een ander protocol gebruiken zoals WebSocket (meer over hen hier) of een vorm van streaming of meer langdurige verbinding.
We kunnen ook een hacky code rondom implementeren om REST eruit te laten zien als streaming. Wat meer is, met behulp van HTTP/1.1 REST vereist één verbinding per aanvraag-antwoord uitwisseling. Zo’n aanpak kan problematisch zijn voor langlopende aanvragen of wanneer we beperkte netwerkmogelijkheden hebben.
Natuurlijk kunnen we HTTP/2 gebruiken voor het bouwen van REST-achtige API’s; echter, niet alle servers en bibliotheken ondersteunen HTTP/2 nog. Daarom kunnen problemen zich in andere plaatsen voordoen.
gRPC, aan de andere kant, gebruikt alleen HTTP/2. Het staat toe om meerdere aanvraag-antwoord paren via één TCP-verbinding te sturen. Zo’n aanpak kan een aanzienlijke prestatieverbetering voor onze applicatie zijn.
- Resultaat: Slight win voor gRPC
Ondersteunde Gegevensformaten
Stel je voor dat REST API standaard gebruik maakt van HTTP/1.1, dan kan het veel formaten ondersteunen.
REST legt over het algemeen geen beperkingen op aangaande berichtformaat en stijl. In feite is elk formaat dat kan worden geserialiseerd naar oude simpele tekst geldig. We kunnen elk formaat gebruiken dat het beste bij een bepaalde situatie past.
Het meest populaire formaat voor het verzenden van gegevens in REST-applicaties is zonder twijfel JSON. XML neemt de tweede plaats in vanwege het grote aantal oudere/legacy applicaties.
Echter, wanneer we REST gebruiken met HTTP/2, dan worden alleen binaire uitwisselingsformaten ondersteund. In dit geval kunnen we Protobuf of Avro gebruiken. Natuurlijk kan zo’n aanpak nadelen hebben, maar daarover meer in de volgende punten.
Ondertussen ondersteunt gRPC slechts twee formaten voor het uitwisselen van gegevens:
- Protobuf – Standaard
- JSON — Als u moet integreren met een oudere API
Als u besluit om met JSON te werken, zal gRPC JSON gebruiken als codering voor berichten en GSON als berichtformaat. Bovendien zal het gebruik van JSON enige extra configuratie vereisen. Hier is de gRPC documentatie over hoe u dat kunt doen.
- Resultaat: Een overwinning voor REST, aangezien het meer formaten ondersteunt.
Gegevensgrootte
Standaard gebruikt gRPC een binaire gegevenstoezeggingsindeling, die de grootte van de berichten die over het netwerk worden verzonden aanzienlijk verkleint: onderzoek suggereert een vermindering met ongeveer 40-50% in bytes — mijn ervaring uit een van de vorige projecten suggereert zelfs een vermindering met 50-70% minder.
Het bovenstaande artikel biedt een relatief diepgaande vergelijking van de grootte tussen JSON en Protobuff. De auteur heeft ook een tool geleverd voor het genereren van JSONs en binaire bestanden. Zo kunt u zijn experimenten opnieuw uitvoeren en de resultaten vergelijken.
De objecten uit het artikel zijn redelijk eenvoudig. Toch is de algemene regel — hoe meer ingesloten objecten en hoe complexer de structuur van JSON, hoe zwaarder het zal zijn in vergelijking met Protobuf. Een verschil van 50% in grootte ten gunste van Protobuf is een goede uitgangspositie.
Het verschil kan worden geminimaliseerd of geëlimineerd bij het gebruik van het binaire uitwisselingsformaat voor REST. Toch is het niet de meest courante of best ondersteunde manier om RESTful APIs te doen, dus andere problemen kunnen optreden.
- Resultaat: In het standaardgeval, overwinning voor gRPC; in het geval van beide met binaire gegevensformaat, een gelijkspel.
Doorvoer
Nogmaals, in het geval van REST, hangt alles af van het onderliggende HTTP-protocol en de server.
In het standaardgeval, REST gebaseerd op HTTP/1.1, zelfs de meest prestatiegerichte server zal niet in staat zijn om de prestaties van gRPC te evenaren, vooral wanneer we de overhead van serialisatie en deserialisatie toevoegen bij het gebruik van JSON. Hoewel de verschillen minder lijken te zijn wanneer we overschakelen naar HTTP/2.
Wat betreft maximale doorvoer, in beide gevallen is HTTP een transportmedium, dus het heeft het potentieel om oneindig te schalen. Dus alles hangt af van de hulpmiddelen die we gebruiken en wat we precies met onze applicatie doen, aangezien er geen beperkingen zijn vanwege het ontwerp.
- Resultaat: In het standaardgeval, gRPC; in het geval van beide met binaire gegevens en HTTP/2, gelijkspel of lichte overwinning voor gRPC.
Definities
In deze sectie zal ik beschrijven hoe we onze berichten en service in beide benaderingen definiëren.
In de meeste REST-toepassingen verklaren we gewoon onze aanvragen en reacties als klassen, objecten, of welke structuur een bepaalde taal ondersteunt. Vervolgens vertrouwen we op voorgestelde bibliotheken voor serialisatie en deserialisatie van JSON/XML/YAML, of welk formaat we nodig hebben.
Bovendien bestaan er aanhoudende inspanningen om tools te creëren die in staat zijn om code te genereren in de programmeertaal van keuze op basis van REST API-definities uit Swagger. Echter lijken ze in de alfaversie te zijn, dus kunnen er nog wel wat bugs en kleine problemen optreden die hen moeilijk te gebruiken maken.
Er is weinig verschil tussen binaire en niet-binaire formaten voor REST-toepassingen, aangezien de regel min of meer hetzelfde is in beide gevallen. Voor het binaire formaat definiëren we gewoon alles op de manier die vereist is door een bepaald formaat.
Daarnaast hebben we onze REST-service gedefinieerd via methoden of annotaties vanuit ons onderliggende bibliotheek of framework. Het hulpmiddel is verder verantwoordelijk voor het ontsluiten ervan samen met andere configuraties aan de buitenwereld.
In het geval van gRPC hebben we Protobuf als standaard en in feite de enige manier om definities te schrijven. We moeten alles declareren: berichten, services en methoden in .proto-bestanden, dus de kwestie is vrij eenvoudig.
Vervolgens gebruiken we het door gRPC geleverde hulpmiddel om code voor ons te genereren, en we hoeven alleen onze methoden te implementeren. Na dat, zou alles moeten werken zoals bedoeld.
Bovendien ondersteunt Protobuf importeren, zodat we onze setup redelijk eenvoudig over meerdere bestanden kunnen verdelen.
- Resultaat: Geen winnaar hier, alleen een beschrijving en een tip van mij: kies de aanpak die het beste bij je past.
Gemak van Overname
In dit deel zal ik de bibliotheek-/frameworkondersteuning voor elke aanpak vergelijken in hedendaagse programmeertalen.
Over het algemeen heb ik in mijn korte carrière als software engineer in elke programmeertaal (Java, Scala, Python) minstens 3 grote bibliotheken/frameworks tegen gekomen voor het maken van REST-achtige applicaties, laat staan een vergelijkbaar aantal bibliotheken voor het parseren van JSON’s naar objecten/klassen.
Daarnaast, omdat REST standaard gebruik maakt van menselijk leesbare formaten, is het gemakkelijker om te debuggen en te werken met voor nieuwelingen. Dit kan ook van invloed zijn op de snelheid van het leveren van nieuwe functies en kan helpen bij het bestrijden van bugs die in je code optreden.
Kortom, de ondersteuning voor REST-stijl applicaties is ten minste zeer goed.
In Scala hebben we zelfs een tool genaamd tapir — waar ik het genoegen had om enige tijd een van de beheerders van te zijn. Tapir stelt ons in staat om onze HTTP-server te abstracteren en eindpunten te schrijven die werken voor meerdere servers.
gRPC zelf biedt een clientbibliotheek voor meer dan 8 populaire programmeertalen. Dit is meestal voldoende, aangezien deze bibliotheken alles bevatten wat nodig is om een gRPC-API te maken. Daarnaast ben ik op de hoogte van bibliotheken die hogere abstracties bieden voor Java (via Spring Boot Starter) en voor Scala.
Nog iets is dat REST tegenwoordig als een wereldwijd standaard wordt beschouwd en een toegangspoort voor het bouwen van services, terwijl RPC en gRPC, in het bijzonder, nog steeds als een noviteit worden gezien ondanks dat ze op dit moment enigszins oud zijn.
- Resultaat: REST, aangezien het meer wijdverbreid is aangenomen en veel meer bibliotheken en frameworks rondom heeft
Tooling Support
Bibliotheken, frameworks en algemene marktaandelen zijn hierboven behandeld, dus in dit deel wil ik de tooling rond beide stijlen behandelen. Het betekent tools voor tests, performance/stress tests en documentatie.
Geautomatiseerde Tests/Tests
Ten eerste, in het geval van REST, zijn tools voor het bouwen van geautomatiseerde tests ingebouwd in verschillende bibliotheken en frameworks of zijn aparte tools die met deze enige doelstelling zijn gebouwd, zoals REST-assured.
In het geval van gRPC kunnen we een stub genereren en deze gebruiken voor tests. Als we zelfs strenger willen zijn, kunnen we de gegenereerde client als een aparte applicatie gebruiken en deze als basis voor onze tests op echte service gebruiken.
Wat betreft externe toolondersteuning voor gRPC, ben ik zich ervan bewust:
- Postman app ondersteuning voor gRPC
- De JetBrains HTTP client die wordt gebruikt in hun IDE’s kan ook gRPC ondersteunen met enige minimale configuratie
- Resultaat één: Overwinning voor REST; echter, de situatie lijkt te verbeteren voor gRPC.
Prestatietests
Hier heeft REST aanzienlijke voordelen, aangezien tools zoals JMeter of Gatling stress tests van REST API’s een redelijk gemakkelijke taak maken.
Helaas heeft gRPC geen zulke ondersteuning. Ik ben zich ervan bewust dat mensen van Gatling de gRPC-plugin hebben opgenomen in de huidige Gatling-release, dus de situatie lijkt te verbeteren.
Echter, tot nu toe hadden we slechts één onofficiële plugin en bibliotheek genaamd ghz. Al deze zijn goed; het is gewoon niet hetzelfde niveau van ondersteuning als voor REST.
- Resultaat twee: Overwinning voor REST; echter, de situatie lijkt te verbeteren voor gRPC, opnieuw 😉
Documentatie
In het geval van API-documentatie, is de overwinning wederom voor REST met OpenAPI en Swagger die breed worden aangenomen in de industrie en de facto standaard zijn. Bijna alle bibliotheken voor REST kunnen swagger-documentatie met minimale inspanning of gewoon uit de doos vertonen.
Helaas heeft gRPC niets dergelijks.
Echter, de vraag is of gRPC überhaupt een hulpmiddel zoals dit nodig heeft. gRPC is vanwege zijn ontwerp descriptiever dan REST, dus extra documentatiegereedschappen kunnen.
Over het algemeen, .proto-bestanden met onze API-beschrijving zijn meer declaratief en compact dan de code die verantwoordelijk is voor het maken van onze REST API-code, dus misschien heeft men geen meer documentatie nodig van gRPC. Het antwoord laat ik aan jou over.
- Resultaat drie: Overwinning voor REST; echter, de vraag naar gRPC-documentatie is open.
Algemeen resultaat:
A significant victory for REST
Samenvatting
Het eindstandenoverzicht ziet er zo uit.

De scores zijn gelijk verdeeld tussen beide stijlen, met drie overwinningen elk en één categorie zonder duidelijke winnaar.
Er is geen gouden greep: denk gewoon na over welke categorieën misschien het belangrijkst zijn voor uw toepassing en kies vervolgens de aanpak die won in de meeste van hen – althans dat is mijn aanbeveling.
Wat mijn voorkeur betreft, geef ik gRPC een kans als ik kan, aangezien het in mijn laatste project behoorlijk goed werkte. Het kan een betere keuze zijn dan de oude vertrouwde REST-makker.
Als je ooit hulp nodig hebt bij het kiezen tussen REST en gRPC of omgaan met een ander soort technisch probleem, laat het me dan weten. Ik kan misschien helpen.
Bedankt voor je tijd.