Auteur: Sander van Laarhoven

Wat is GraphQL?

Steeds vaker kom je GraphQL tegen bij conferenties en implementaties van software. Wat is het nou eigenlijk, en wat zijn de voor- en nadelen van het gebruik ervan. Dat wordt hopelijk in dit stuk een beetje duidelijker. Het is geen cursus maar geeft wel een beetje een idee van hoe het werkt en of het geschikt zou zijn voor een bepaalde situatie.

Oorsprong

GraphQL is een zogenaamde "data query language". Het is gemaakt om krachtige queries te kunnen doen naar de backend, terwijl het nog steeds gemakkelijk te gebruiken en te leren is door ontwikkelaars.

Het is in eerste instantie ontstaan als een intern project voor en door Facebook (2012) en daarna opengesteld voor het publieke gebruik (2015) (https://engineering.fb.com/201...). Hierna heeft de open source community het product omarmd en er runtimes voor gebouwd in verschillende talen, onder andere: Go, Ruby, Scala, Java, .Net en Python.

Wat is GraphQL

We gebruiken een simpele applicatie als voorbeeld:
In een sales applicatie wordt de naam van de salesmedewerker op het scherm getoond. Natuurlijk willen we verder niet alleen de naam van de medewerker zien in dit scherm maar we willen ook zijn omzetgegevens hebben voor de afgelopen twee jaar om bovenaan de pagina te tonen. En om een overzicht te geven van zijn recentste accounts halen we ook zijn accounts op van de server.

Dit zou het plaatje zijn voor de beschreven functionaliteit gebruik makend van GraphQL:

In de query van de GraphQL request geef je aan wat je opvraagt van de server, in dit geval een "user" met id: "k7690cbl789

Vervolgens geef je aan welke informatie je voor deze user terug wilt krijgen.

Je krijg daarmee dus niet meer of minder dan de informatie die echt nodig hebt in dat specifieke geval. En dit alles zonder een nieuwe service te maken op de server.

GraphQL gebruikt een "strong type system" om de definitie van de API vast te leggen. Alle types die worden opengesteld via de API worden in het schema gezet gebruik makend van de GraphQL Schema Definition Language (SDL). Dit schema fungeert als contract tussen de client en de server voor hoe een client de data kan bevragen.

Een voorbeeld van zo’n schema voor "user" zou bijvoorbeeld zijn:

Hiermee weten alle betrokken partijen zeker dat een "name" veld in ieder geval altijd een "String" is of moet zijn. Als er voor het aanmaken van een nieuwe "user" dus een ander type veld wordt aangeboden zal de validatie in de service automatisch aangeven dat dat niet kan omdat het veld alleen een "String" kan zijn.

GraphQL werkt voor iedere ontwikkelaar altijd hetzelfde dus is het enorm voorspelbaar en zijn er veel minder misverstanden en miscommunicaties over implementaties.

Het is niet alleen zo dat we meerdere dingen tegelijk op kunnen halen van één specifiek element. Alle data die ontsloten is kan tegelijk worden opgevraagd. Er is namelijk één URL (GraphQL endpoint) waar men mee communiceert. Door een query mee te sturen in de request naar het GraphQL endpoint geef je aan wat je graag wil ontvangen van de server.

Als ik bijvoorbeeld alle accounts, gebruikers en bedrijfsfietsen van een bedrijf zou willen hebben en deze zijn ontsloten via het endpoint zou ik dat in één enkele request kunnen doen:

Bij GraphQL is de structuur van de data beschreven in het schema. Hierdoor zien we dat zowel in de query als de response dezelfde datastructuur wordt aangehouden. De elementen worden binnen deze structuur hiërarchisch weergegeven doordat ze ook op deze manier in het schema zijn opgenomen.

Er zijn twee soorten operaties mogelijk binnen GraphQL. Tot nu toe hebben we het alleen nog gehad over een query maar natuurlijk kunnen er ook zaken worden opgeslagen via het protocol. Aanmaken, aanpassen en verwijderen van data wordt gedaan met behulp van een mutation. In een mutation kunnen query variabelen mee worden gegeven die worden gebruikt om de data aan te passen.


Een mutation om de gegevens van een gebruiker aan te passen zou er bijvoorbeeld op deze manier uit kunnen zien:






De informatie kan hierbij worden meegegeven met query variables:





In de browser zal dat vertaald worden naar wederom een POST met een request payload:






Alleen een communicatieprotocol

GraphQL is puur een communicatieprotocol en zegt niets over de manier waarom de data is opgeslagen. Het kan dat ook bovenop een bestaande backend worden gebruikt waarin dit allemaal al is gemaakt.

Een GraphQL runtime kan gebruik maken van bestaande REST services en deze als GraphQL endpoint ontsluiten naar een frontend. Dit kan zelfs met meerdere REST API’s tegelijk.

Zo kan er bijvoorbeeld een adres opgehaald worden en het actuele lokale weer via een andere bron. En dat alles in één request.


Foutafhandeling

GraphQL gebruikt een "strong type system" om de definitie van de API vast te leggen. Alle types die worden opengesteld via de API worden in het schema gezet gebruik makend van de GraphQL Schema Definition Language (SDL). Dit schema fungeert als contract tussen de client en de server voor hoe een client de data kan bevragen. Als er dus wordt gecommuniceerd op een manier die niet voldoet aan het gedefinieerde schema kan er een gestructureerde specifieke foutmelding worden gegenereerd door GraphQL die precies aangeeft wat er niet klopt. Ontwikkelaars hoeven dit hierdoor niet zelf te maken zoals bij een REST service en kunnen ervan uitgaan dat data voldoet aan de criteria in het schema.


Performance

Natuurlijk is er een kleine performance penalty bij het implementeren van GraphQL omdat het een extra stukje software is boven op de data op de server.

Het niet hoeven doen van meerdere requests maar alles in 1 request op kunnen halen biedt wel erg veel performance winst, hoewel het maken van een specifieke REST API gemaakt voor dat specifieke doel natuurlijk nog sneller kan zijn.

Hiernaast is er geen overfetching (het downloaden van data die je niet gebruikt) waardoor de bandbreedte en beide systemen minder worden belast.

Underfetching is met GraphQL ook geen issue aangezien alle data meteen kan worden opgevraagd in één request en er dus geen extra informatie hoeft te worden opgehaald als uitbereiding op eerder opgehaalde data.

Een nadeel is dat alle combinaties van data kunnen worden opgevraagd en het dus erg moeilijk is om te voorspellen hoe veel en welke data elke request zal opvragen van de server. Het kan dus zo zijn dat bepaalde request of combinaties van requests erg zwaar blijken te zijn voor de server. Dit maakt optimalisatie van requests ook moeilijker.

Het cachen van GraphQL requests is een stuk complexer dan bij bijvoorbeeld REST. Normaal wordt gecached op basis van een unieke URL, bijvoorbeeld: "/V1/users/<id>". Bij GraphQL is dat niet mogelijk omdat de endpoint altijd hetzelfde is. Het zal dus moet gebeuren op basis van de query in de body van POST die GraphQL doet. GraphQL API’s creëren daarom zelf zo’n unieke identifier uit de request payload. Hoewel het hierdoor mogelijk is requests te cachen met GraphQL zijn er natuurlijk vele malen meer combinaties van velden mogelijk dan bij een REST API en zal het potentieel daardoor minder effectief zijn.

Gebruik van GraphQL heeft de neiging om zwaar(der) te zijn voor de server en daardoor wordt caching en optimalisatie extra belangrijk


Sneller onafhankelijk kunnen ontwikkelen

Niet in alle situaties kun je als frontend ontwikkelaar direct snel schakelen met de ontwikkelaar(s) van de backend of is de backend zelfs in eigen beheer. Dit maakt het soms lastig om gewenste wijzigingen op een service voor functionaliteit in de frontend snel voor elkaar te krijgen. Hierdoor ontstaan vaak vertragingen in een ontwikkeltraject.

Als meerdere partijen gebruik maken van dezelfde API, de backend en frontend ontwikkelaars werken in een ander tempo of niet in eenzelfde team kan het ook lastig zijn om services te veranderen. De software aan de andere kant zou door de aanpassing tenslotte niet meer kunnen werken.

Bij GraphQL ben je volledig vrij om andere data aan te spreken binnen hetgeen beschikbaar is gesteld zonder dat de service moet worden aangepast. Dat maakt dat ontwikkelaars van de verschillende lagen van een applicatie minder vaak hoeven te overleggen en veel onafhankelijker kunnen opereren.


Documentatie

Waar het vaak bij software ontbreekt aan goede documentatie is dat bij GraphQL door het schema en type systeem al "out of the box" geregeld.

Doordat alles al in de schema’s is vastgelegd kan GraphQL zelf documentatie genereren. De gebruikte tool waarmee query’s en mutaties kunnen worden geschreven, uitgeprobeerd en waarin de documentatie kan worden bekeken is GraphiQL.

Hiermee is de documentatie altijd actueel en is overdracht veel minder intensief tussen de backend en frontend ontwikkelaars. Nadat het schema is opgesteld kunnen beide partijen onafhankelijk aan de slag.


Analytics

Doordat een client altijd alleen op zal halen wat hij nodig heeft kan er op de backend ook veel specifieker worden bekeken welke data wordt gebruikt. Zo kunnen bijvoorbeeld velden die nooit worden gebruikt op termijn worden verwijderd.

GraphQL gebruikt zogenaamde "resolver functions" om data te verzamelen. Door de performance van deze "resolver functions" te monitoren kunnen gemakkelijker verbeterpunten in het achterliggende systeem worden opgespoord.


Flexibiliteit

Aan de frontend is werken met GraphQL erg flexibel omdat je alles kunt opvragen in alle combinaties die je zou willen. Aan de backend is dat wat minder omdat men daar ook het schema moet maken en vervolgens volgens het schema moet werken. Dit zeggende zijn er tegenwoordig wel al een hele hoop manieren om zaken te genereren. Dit wordt mogelijk gemaakt door het strongly typed schema van GraphQL. Dat reduceert een hoop complexiteit maar het is nog steeds complexer dan bijvoorbeeld het maken van een REST service.


Complexiteit

Hoewel werken met GraphQL aan de frontend erg gemakkelijk en overzichtelijk is geeft het aan de backend wel wat extra complexiteit en er moet natuurlijk een schema moet worden gemaakt. Optimalisatie van requests is in de backend ook lastiger aangezien niet te voorspellen is welke data tegelijk wordt opgevraagd. Natuurlijk kunnen query’s die regelmatig terugkomen of minder performant blijken te zijn alsnog worden geoptimaliseerd. Dat zal dan moeten blijken uit de analytics en maakt monitoren dus extra belangrijk.


Toepasbaarheid

GraphQL is in het bijzonder geschikt als er een duidelijke scheiding is tussen frontend en backend teams of dat zelfs door verschillende partijen wordt gedaan. Ook is het zeer geschikt om een API mee te ontsluiten naar de buitenwereld buiten de invloedsfeer van de partij die de data ontsluit. Voor zeer kleine REST API’s of REST API’s die uitzonderlijk vaak worden aangeroepen en nooit wijzigen maakt de extra complexiteit en de performance penalty het wat minder geschikt. Daarbij kan natuurlijk nog steeds gekozen worden voor GraphQL omdat de ontwikkelaars alleen gewend zijn om hiermee te werken of omdat het de standaard is.

Specifiekere vragen?

Vul uw e-mailadres in en Oliver IT neemt zo spoedig mogelijk contact met u op!

Gelukt! We nemen spoedig contact met u op!
Gerben Moerland Partner
Gerben Moerland