GraphQL best practices
GraphQL is volwassen genoeg, en bestaat al lang genoeg, dat de community veel artikelen over best practices heeft gepubliceerd. Deze gidsen behandelen vrijwel alle aspecten van GraphQL, waaronder schemaontwerp, naamgevingsconventies, beveiligingsaanpak en het geven van zinvolle foutmeldingen, onder andere.
Dit zijn enkele van de meest waardevolle gidsen over best practices in GraphQL.
Best practices op graphql.org
De officiƫle GraphQL-site biedt een algemene inleiding tot best practices in GraphQL.
Deze onderwerpen behandelen voornamelijk kwesties op hoog niveau, zoals:
- Wat is de beste manier om resultaten te pagineren
- Waar de GraphQL-laag zich bevindt binnen de architectuur
- Hoe je de Node-interface gebruikt voor globale objectidentificatie
- Hoe je resultaten cachet
- En nog veel meer

Aanbevelingen van Lee Byron
Niet lang na het uitbrengen van GraphQL publiceerde GraphQL-bedenker Lee Byron het artikel Lessons From 4 Years of GraphQL, waarin hij beschrijft hoe we conceptueel met GraphQL zouden moeten werken:
- Naamgeving doet ertoe
- Denk in grafen, niet in endpoints
- Beschrijf de data, niet de weergave
- GraphQL is een lichte interface
- Verberg implementatiedetails
Hij beschrijft ook uitgebreid verschillende waardevolle principes en lessen die hij leerde tijdens het gebruik van GraphQL bij Facebook.
GraphQL Rules
GraphQL Rules is een site speciaal gewijd aan het presenteren van dagelijkse best practices voor het werken met GraphQL, voornamelijk met betrekking tot het ontwerp van het GraphQL-schema.
Deze bron is zeer uitgebreid. Het bundelt informatie uit een aantal uitzonderlijke bronnen (zoals het artikel Designing GraphQL Mutations en Shopify's tutorial Designing a GraphQL API) en presenteert ze samen op een beknopte manier.
De beschreven regels omvatten:
- Naamgevingsregels
- Gebruik
camelCasevoor GraphQL-velden en -argumenten. - Gebruik
UpperCamelCasevoor GraphQL-typen. - Gebruik
CAPITALIZED_WITH_UNDERSCORESvoor het benoemen van ENUM-typen.
- Gebruik
- Typeregels
- Gebruik aangepaste scalaire typen als je velden of argumenten met een specifieke semantische waarde wilt declareren.
- Gebruik Enum voor velden die een specifieke set waarden bevatten.
- Veldregels (Output)
- Gebruik semantische namen voor velden en vermijd het lekken van implementatiedetails in veldnamen.
- Gebruik een
Non-Null-veld als een veld altijd een bepaalde waarde heeft. - Groepeer zoveel mogelijk gerelateerde velden in een aangepast objecttype.
- Argumentregels (Input)
- Groepeer gekoppelde argumenten in een nieuw input-type.
- Gebruik strikte scalaire typen voor argumenten, bijv.
DateTimein plaats vanString. - Markeer argumenten als
requiredals ze vereist zijn voor de uitvoering van queries.
- Lijstregels
- Gebruik het argument
filtervoor het filteren van lijsten, dat alle beschikbare filters bevat. - Gebruik het argument
sortvan het typeEnumof[Enum!]voor het sorteren van lijsten. - Gebruik
limitmet een standaardwaarde enskipom het aantal geretourneerde items in een lijst te beperken. - Gebruik argumenten
page,perPagevoor paginering en geef een uitvoertype terug metitems(een array van elementen) enpageInfo(metadata). - Gebruik voor oneindige lijsten (oneindig scrollen) de Relay Cursor Connections Specification.
- Gebruik het argument
- Mutation-regels
- Gebruik Namespace-types om mutations te groeperen binnen ƩƩn resource.
- Ga verder dan CRUD ā maak kleine mutations voor verschillende bedrijfsoperaties op resources.
- Overweeg de mogelijkheid om mutations op meerdere items uit te voeren (batch-wijzigingen van hetzelfde type).
- Mutations moeten alle verplichte argumenten duidelijk beschrijven; er mogen geen of-of-opties zijn.
- Zet in mutations alle variabelen in ƩƩn uniek input-argument.
- Elke mutation moet een uniek payload-type hebben.
Best practices voor resolvers
Het artikel GraphQL Resolvers: Best Practices beschrijft hoe je veldresolvers het beste kunt maken. Hoewel het gericht is op Node.js-servers (PayPals infrastructuur is gebaseerd op Express), zijn veel van de lessen ook toepasbaar op andere technologieƫn, waaronder PHP.
De belangrijkste inzichten zijn:
- Het ophalen en doorgeven van data van ouder naar kind moet spaarzaam worden gebruikt.
- Gebruik bibliotheken zoals dataloader om downstream-verzoeken te dedupliceren.
- Wees je bewust van de druk die je legt op je databronnen.
- Muteer "context" niet. Dit zorgt voor consistente, minder foutgevoelige code.
- Schrijf resolvers die leesbaar, onderhoudbaar en testbaar zijn. Niet te slim.
- Maak je resolvers zo dun mogelijk. Extraheer de logica voor het ophalen van data naar herbruikbare async-functies.
OWASP - GraphQL Cheat Sheet
OWASP (Open Web Application Security Project) is een non-profitorganisatie die werkt aan het verbeteren van de beveiliging van software. Het doet onderzoek naar hoe verschillende technologieƫn kwetsbaar zijn voor exploits, en beschrijft uitgebreid oplossingen voor beveiligingsproblemen, zodat het voor ontwikkelaars gemakkelijker wordt aanvallen te voorkomen.
OWASP heeft de GraphQL Cheat Sheet gepubliceerd, met uitleg over de meest voorkomende aanvallen en grootste beveiligingsproblemen in GraphQL, en hoe je deze kunt aanpakken.
Veelvoorkomende aanvallen op GraphQL zijn:
- Injection - dit omvat meestal, maar is niet beperkt tot:
- SQL- en NoSQL-injection
- OS Command-injection
- SSRF- en CRLF-injection/Request Smuggling
- DoS (Denial of Service)
- Misbruik van gebrekkige autorisatie: onjuiste of buitensporige toegang, inclusief IDOR
- Batching Attacks, een GraphQL-specifieke methode van brute force-aanvallen
- Misbruik van onveilige standaardconfiguraties
OWASP geeft vervolgens aanbevelingen over hoe elk van deze gevallen te vermijden.
Best practices met GraphQL queries
Het Apollo-team publiceerde de GraphQL query best practices, met praktische inzichten over manieren om GraphQL queries samen te stellen.
Zo bereiken deze twee queries hetzelfde doel, maar omdat de eerste een operatienaam heeft, is hij begrijpelijker en handiger bij het debuggen:
# Aanbevolen ā
query GetBooks {
books {
title
}
}
# Niet aanbevolen ā
query {
books {
title
}
}Hun suggesties omvatten:
- Geef alle operaties een naam
- Gebruik variabelen om GraphQL-argumenten door te geven
- Haal alleen de data op die je nodig hebt, waar je die nodig hebt
- Gebruik fragments om gerelateerde sets velden te encapsuleren
- Haal globale data en gebruikersspecifieke data apart op
De one graph benutten
Ook van het Apollo-team is de site Principled GraphQL, die uitlegt dat GraphQL niet alleen een specificatie is, maar ā misschien nog belangrijker ā een interface om te communiceren met de data-"graaf" van ons bedrijf.
Via een lijst van 10 principes beschrijft deze site hoe je het meeste uit de enkele graaf kunt halen:
- One Graph: je bedrijf moet ƩƩn uniforme graaf hebben, in plaats van meerdere grafen die door elk team worden aangemaakt.
- Federated Implementation: hoewel er maar ƩƩn graaf is, moet de implementatie van die graaf gefedereerd zijn over meerdere teams.
- Track the Schema in a Registry: er moet ƩƩn bron van waarheid zijn voor het registreren en bijhouden van de graaf.
- Abstract, Demand-Oriented Schema: het schema moet fungeren als een abstractielaag die flexibiliteit biedt aan consumenten, terwijl het implementatiedetails van services verbergt.
- Use an Agile Approach to Schema Development: het schema moet incrementeel worden opgebouwd op basis van werkelijke vereisten en soepel evolueren in de loop van de tijd.
- Iteratively Improve Performance: prestatiebeheer moet een continu, datagedreven proces zijn dat soepel aanpast aan veranderende queries-belastingen en service-implementaties.
- Use Graph Metadata to Empower Developers: ontwikkelaars moeten gedurende het hele ontwikkelingsproces uitgebreid inzicht hebben in de graaf.
- Access and Demand Control: verleen toegang tot de graaf op basis van de client, en beheer wat en hoe clients er toegang toe hebben.
- Structured Logging: leg gestructureerde logs vast van alle graafoperaties en gebruik ze als het primaire hulpmiddel voor het begrijpen van het gebruik van de graaf.
- Separate the GraphQL Layer from the Service Layer: pas een gelaagde architectuur toe waarbij de graaffunctionaliteit is ondergebracht in een aparte laag in plaats van ingebakken in elke service.