Bronnen
BronnenGraphQL best practices

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:

Waar de GraphQL-laag is geplaatst binnen de architectuur

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:

  1. Naamgevingsregels
    • Gebruik camelCase voor GraphQL-velden en -argumenten.
    • Gebruik UpperCamelCase voor GraphQL-typen.
    • Gebruik CAPITALIZED_WITH_UNDERSCORES voor het benoemen van ENUM-typen.
  2. 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.
  3. 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.
  4. Argumentregels (Input)
    • Groepeer gekoppelde argumenten in een nieuw input-type.
    • Gebruik strikte scalaire typen voor argumenten, bijv. DateTime in plaats van String.
    • Markeer argumenten als required als ze vereist zijn voor de uitvoering van queries.
  5. Lijstregels
    • Gebruik het argument filter voor het filteren van lijsten, dat alle beschikbare filters bevat.
    • Gebruik het argument sort van het type Enum of [Enum!] voor het sorteren van lijsten.
    • Gebruik limit met een standaardwaarde en skip om het aantal geretourneerde items in een lijst te beperken.
    • Gebruik argumenten page, perPage voor paginering en geef een uitvoertype terug met items (een array van elementen) en pageInfo (metadata).
    • Gebruik voor oneindige lijsten (oneindig scrollen) de Relay Cursor Connections Specification.
  6. 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:

  1. Injection - dit omvat meestal, maar is niet beperkt tot:
    • SQL- en NoSQL-injection
    • OS Command-injection
    • SSRF- en CRLF-injection/Request Smuggling
  2. DoS (Denial of Service)
  3. Misbruik van gebrekkige autorisatie: onjuiste of buitensporige toegang, inclusief IDOR
  4. Batching Attacks, een GraphQL-specifieke methode van brute force-aanvallen
  5. 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:

  1. One Graph: je bedrijf moet ƩƩn uniforme graaf hebben, in plaats van meerdere grafen die door elk team worden aangemaakt.
  2. Federated Implementation: hoewel er maar ƩƩn graaf is, moet de implementatie van die graaf gefedereerd zijn over meerdere teams.
  3. Track the Schema in a Registry: er moet ƩƩn bron van waarheid zijn voor het registreren en bijhouden van de graaf.
  4. Abstract, Demand-Oriented Schema: het schema moet fungeren als een abstractielaag die flexibiliteit biedt aan consumenten, terwijl het implementatiedetails van services verbergt.
  5. 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.
  6. Iteratively Improve Performance: prestatiebeheer moet een continu, datagedreven proces zijn dat soepel aanpast aan veranderende queries-belastingen en service-implementaties.
  7. Use Graph Metadata to Empower Developers: ontwikkelaars moeten gedurende het hele ontwikkelingsproces uitgebreid inzicht hebben in de graaf.
  8. Access and Demand Control: verleen toegang tot de graaf op basis van de client, en beheer wat en hoe clients er toegang toe hebben.
  9. 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.
  10. 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.