Axxes IT Consultancy

5 manieren om een GraphQL web server te implementeren

Mijn verhaal begint een goede 2jaar geleden op de eerste editie van Haxx waar ik voor het eerst de term “GraphQL” heb gehoord. Web services bouwen via REST is tegenwoordig alomtegenwoordig, hierbij vraag je via een HTTP request een specifiek resource op. Daarentegen een service aanroepen met als doel om alle gewenste informatie in een specifiek formaat terug te krijgen, zonder dit formaat expliciet in de backend te definiëren. Dat was een nieuw gegeven en intrigeerde me enorm.

Hoewel ik al vele talks gezien heb, ontbrak steeds hoe je een GraphQL service begint te bouwen. Zoals bij vele frameworks/libraries begon mijn zoektocht op de officiële website van GraphQL waar je voor dit soort vragen al snel doorverwezen wordt naar een andere site: https://www.howtographql.com. Op dit platform kan men stap voor stap leren hoe je een GraphQL server opzet of aanspreekt, zowel backend als frontend dus.

Het voorbeeld

Het voorbeeld dat ik hier gebruik om 5 mogelijke configuraties te tonen is dat van een employee-service. Aan deze service kan je de huidige werknemers opvragen, alsook werknemers toevoegen.

Elke configuratie biedt steeds een endpoint aan die het mogelijk maakt de GraphQL server eenvoudig te bevragen. Je vindt deze terug onder /graphiql (of /gui in de graphql-spqr-spring-boot-starter module)

Er wordt 1 query aangeboden: allEmployees (met als optionele parameter: competenceCenter).
Deze query doet wat zijn naam doet vermoeden en geeft alle werknemers van een competence center terug. Indien er geen parameter wordt meegegeven krijg je gewoon alle werknemers terug.

Een mogelijke query ziet er als volgt uit:

Query GraphQL web server

Naast het opvragen van data is ook mogelijk om nieuwe data toe te voegen via volgende mutatie: createEmployee (met als verplichte parameters: firstName, lastName, email en competenceCenter)

Mutation GraphQL web server

Alle uitgewerkte voorbeelden zijn steeds terug te vinden in mijn github repository onder:
https://github.com/ArnoTurelinckx/graphql-server-tutorial

De uitwerking

Het opzetten van een GraphQL backend bestaat steeds uit volgende stappen:

  1. Het opzetten van een schema waarin types, queries, mutations,… beschreven staan.
    Dit kan enerzijds door gebruik te maken van de Schema Definition Language (SDL),
    waarbij men het schema bijhoud in een file (schema.graphqls).
    Het alternatief is om het schema in de code te (laten) genereren.
  2. Het aanmaken van data classen (POJOs), deze objecten representeren de types in het GraphQL schema.
  3. Het aanmaken van een Query-class die de Query in ons schema weerspiegelt. In tegenstelling tot POJOs, moeten we voor aan de Query objecten methodes toevoegen. Deze methodes zullen gelinked worden aan de query-resolvers in ons schema.
  4. Een servlet aanmaken die de GraphQL API beschikbaar stelt. En de resolvers koppelt aan het schema.

Er zijn echter een aantal verschillende manieren om deze setup te bereiken.
Laat ons beginnen bij wat de “howtographql” website ons wil laten doen.

1. graphql-java-servlet

De tutorial gaat ervan uit dat de volgende dependencies beschikbaar zijn:

  • graphql-java (bevat de GraphQL implementatie voor java)
  • graphql-java-tools (vereenvoudigt de configuratie van resolvers en het parsen van het schema)
  • graphql-java-servlet (bevat de servlet specificatie voor het aanbieden van ons /graphql endpoint)

De configuratie voor het GraphQL endpoint wordt geïllustreerd in volgende afbeelding.

GraphQLEndpoint

We extenden de SimpleGraphQLHttpServlet en configureren met behulp van een builder waar het schema zich op het classpath bevind (in dit geval schema.graphqls) en welke resolvers gebruikt dienen te worden.

Deze servlet registreren we vervolgens in onze spring applicatie door middel van een Bean:

Bean GraphQL

Deze setup werkt, maar er zijn een aantal bemerkingen die in mij opkomen als spring boot liefhebber.

Het opzetten en registreren van een endpoint is een taak, die iedereen die een GraphQL backend bouwt moet doen . Ook de GraphQLConfiguratie zal door iedere ontwikkelaar opnieuw geschreven moeten worden, en zal er in 99% van de gevallen hetzelfde uitzien.

2. graphql-spring-boot-starter

Een oplossing voor het eerste probleem kan de graphql-java-spring-boot-starter-webmvc library zijn, deze zal een endpoint in jouw plaats configureren. Helaas bied deze dependency geen antwoord op de tweede vraag, en dienen we dan alsnog zelf een GraphQL bean te configureren en registreren. Dit is waar de graphql-spring-boot-starter een antwoord op geeft.

De auto-configuration class die meekomt met graphql-java-tools gaat op zoek naar alle bestanden op het classpath genaamd: *.graphqls dit is editeerbaar door de property: graphql.tools.schema-location-pattern aan te passen naar het gewenste patroon.

Indien er manueel geen GraphQLSchema bean is gedefinieerd, dan zal er een geregistreerd worden door de GraphQLJavaToolsAutoConfiguration class.

Let er ook op dat je alle GraphQLResolvers registreert als bean aangezien ze samen met het schema worden gebruikt om een GraphQLSchema op te bouwen.

Dankzij de graphql-spring-boot-starter moeten we veel minder boilerplate code schrijven.

3. Code-first GraphQL SPQR

Een andere manier van werken is om niet te vertrekken van een schema, dat met behulp van de Schema Definition Language (SDL) is uitgeschreven in een file (schema-first). In plaats daarvan kan men ervoor kiezen om code-first te werken. Concreet wil dit zeggen dat men niet manueel een schema zal uitschrijven, maar het schema laat genereren aan de hand van je code.

Deze aanpak heeft als voordeel dat men objecten niet zowel in het schema (type) als in code (object)
hoeft te definiëren. Een aanpassing in de code reflecteert dus meteen in het schema.

Dit is ook meteen een mogelijk nadeel van het werken op deze manier. Je creëert als het ware een afhankelijkheid tussen de server en de client op deze manier.

Als je toch deze manier van werken prefereert kan GraphQL SPQR hierbij helpen.
Deze library zorgt ervoor dat men POJOs, Queries, Mutation, … kan annoteren (en op die manier metadata kan voorzien) om genoeg informatie te verzamelen om het schema te kunnen genereren.

De annotaties zien er als volgt uit:

GraphQL Mutation

Het enige dat we nu nog moeten doen is het schema laten genereren, dit kan door middel van de meegeleverde GraphQLSchemaGenerator als volgt:

Bean GraphQL Schema Generator

Aangezien we nu niet de graphql-spring-boot-starter gebruiken dienen we nog wel zelf een endpoint te voorzien voor onze server. We zouden opnieuw gebruik kunnen maken van de servlet of graphql-java-spring-boot-starter-webmvc aanpak, maar ik koos er ditmaal voor een klassieke restcontroller te registreren, om aan te tonen dat dit ook een mogelijkheid is.

4. Code-first GraphQL SPQR spring-boot-starter

Indien je graag gebruik wil maken van de GraphQL SPQR library, maar geen zin hebt om zelf een controller te voorzien is er nog een oplossing voorzien… Je had het waarschijnlijk al zien aankomen; de graphql-spqr-spring-boot-starter library.

Laat me beginnen met te zeggen dat deze library nog in zijn experimentele fase zit en dus voorzichtig gebruikt dient te worden. Zo botste ik meteen op een gekend probleem bij het gebruik van graphiQL, dit is dus de enige module in de github repo waar ik gebruik maak van graphql-playground (beschikbaar onder /gui) om toch een UI aan te bieden.

Graphql-spqr-spring-boot-starter maakt het mogelijk een GraphQLApi beschikbaar te stellen waarin je de nodige Query, Mutation en Subscription methodes kan annoteren en op die manier voldoende informatie geeft om het schema op te stellen en de nodige resolvers te laten genereren.

GraphQL Api

Als je liever niet elke methode annoteert om aan te geven of het om een Query, Mutation of Subscription gaat kan je ook voor een andere ResolverBuilder kiezen. Zo worden er ook standaard meegeleverd die naar de access modifiers van de methodes kijkt, of naar de getters en setters.

De graphQL controller wordt u ditmaal aangeboden door de SpqrMvcAutoConfiguration.

5. GraphQL-Kotlin

De laatste library die ik graag zou willen aanhalen werd geschreven door de Expedia Group.

Zij schreven een aantal libraries om het voor Kotlin developers eenvoudiger te maken om een graphQL server op te zetten. Ik heb gebruik gemaakt van graphql-kotlin-spring-server.

Deze library gaat met behulp van de Spring Boot Autoconfiguratie de nodige beans registreren om een reactive GraphQL web server op te zetten. Dit houdt in dat bij het opstarten van de applicatie eerst op zoek gegaan wordt naar objecten die nodig zijn om het schema samen te stellen: types, queries, mutations, subscriptions,… Om dit te kunnen doen moet er wel een application property toegevoegd worden die onze applicatie vertelt welke packages er gescand moeten worden. In ons voorbeeld doen we dit in de application.yml

GraphQL Kotlin

Eenmaal dit gedaan is, kan de library zelf bepalen hoe het schema eruit moet zien. Een leuk voordeel van Kotlin te gebruiken is dat we niet met behulp van annotaties moeten aangeven of objecten nullable zijn of niet. Dit zit namelijk in de taal ingebakken!

Graphql-kotlin-spring-server komt standaard met “Prisma Labs Playground GraphQL” beschikbaar onder /playground. Maar omdat ik dit voor alle andere libraries ook gedaan had wou ik graag graphiql ook aanbieden onder /graphiql. Helaas verwacht de graphiql-spring-boot-starter library een dispatcher servlet, maar aangezien onze webserver nu reactive is, is deze niet beschikbaar.

Daarom registreer ik zelf een reactive route, die de graphiql pagina alsnog beschikbaar stelt onder /graphiql.

GraphQL Kotlin Spring Server

SLOT

Dat was het dan, 5 verschillende manieren. Dit zijn zeker niet de enige manieren, en ze hoeven ook niet los van elkaar gebruikt te worden.

De broncode van de voorbeelden die gebruikt werden in deze blog kan je terugvinden onder https://github.com/ArnoTurelinckx/graphql-server-tutorial

Over de auteur

Arno Turelinckx

Arno Turelinckx

Java Developer

Deel dit artikel

LEER ONS BETER KENNEN

Maak alvast beter kennis met Axxes en onze bedrijfscultuur!

Op zoek naar of ben je een GraphQL expert?

Neem contact op!

Blijf op de hoogte van nieuws en updates in de sector