Skip to content

Commit 1d69d30

Browse files
committed
Add GraphQL blog series and publish part 1
Four-part series "GraphQL onder de loep" for developer.overheid.nl, plus a kennisbank reference page on GraphQL and the graphql tag. Part 1 is published (30 July 2026); parts 2 to 4 stay in blog/draft with staged cross-links. Part 1 introduces GraphQL as a different model from REST. Part 2 covers what the flexible querying costs at runtime: unpredictable load, a larger attack surface, caching you build yourself. Part 3 covers design time: pagination, filtering, error handling, custom scalars and authorization are design work rather than convention. Part 4 weighs it up along seven factors, places the choice in the Dutch government context, and lists what choosing GraphQL requires. One correction worth noting: the ADR and the OAS have a functional scope limited to REST APIs, and Forum Standaardisatie states the ADR does not mandate REST. Choosing GraphQL therefore falls outside their scope, which means there is nothing to explain under 'pas toe of leg uit', but also no established framework and no conformance check to fall back on. Part 4 and the kennisbank page quote both scopes and draw that conclusion.
1 parent 8ed99bd commit 1d69d30

9 files changed

Lines changed: 1486 additions & 0 deletions

File tree

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@developer-overheid-nl/website": minor
3+
---
4+
5+
Voeg blogserie "GraphQL onder de loep" toe (vier delen, als draft) plus een
6+
kennisbankartikel over GraphQL en de tag `graphql`
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@developer-overheid-nl/website": patch
3+
---
4+
5+
Publish GraphQL blog series part 1
Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
---
2+
authors: [joost-farla]
3+
tags: [api, api-design, graphql, rest]
4+
image: /img/graphql-onder-de-loep.jpg
5+
description: |
6+
GraphQL komt regelmatig voorbij in gesprekken over API's binnen de
7+
overheid, maar wat is het eigenlijk precies? In het eerste deel van deze
8+
vierdelige serie maken we kennis met de bouwstenen van GraphQL en laten we
9+
zien waarom het geen "betere REST" is, maar een fundamenteel ander model
10+
voor het ontsluiten van data.
11+
---
12+
13+
# GraphQL onder de loep (deel 1): een kennismaking
14+
15+
![GraphQL onder de loep](/img/graphql-onder-de-loep.jpg)
16+
17+
In gesprekken over API's binnen de overheid komt GraphQL regelmatig voorbij.
18+
Sommige organisaties experimenteren ermee, grote internationale platformen zoals
19+
GitHub en Shopify bieden er publieke API's mee aan, en tegelijkertijd is het
20+
binnen de Nederlandse overheid nog nauwelijks zichtbaar: het
21+
[API-register](/blog/2025/06/18/het-nieuwe-api-register) op deze site is bewust
22+
REST-only, en de
23+
[REST API Design Rules](/kennisbank/api-ontwikkeling/standaarden/api-design-rules)
24+
(ADR) zijn, de naam zegt het al, geschreven voor REST.
25+
26+
Reden genoeg om GraphQL eens grondig onder de loep te nemen. In een serie van
27+
vier blogposts verkennen we wat GraphQL is, wat het oplost, welke uitdagingen
28+
het met zich meebrengt en, als kernvraag, wanneer je het wel en wanneer je het
29+
beter niet kunt gebruiken.
30+
31+
<!-- truncate -->
32+
33+
:::success[TL;DR]
34+
35+
GraphQL is een getypeerde querytaal en runtime voor API's: de client beschrijft
36+
exact welke data hij nodig heeft en krijgt precies dat terug, via één endpoint.
37+
Dat is een fundamenteel ander model dan REST, dat draait om resources en de
38+
semantiek van HTTP. Dit paradigmaverschil verklaart zowel de voordelen als de
39+
uitdagingen van GraphQL.
40+
41+
:::
42+
43+
## Wat is GraphQL?
44+
45+
[GraphQL](https://graphql.org/) is een querytaal voor API's, gecombineerd met
46+
een schemataal om een sterk getypeerd datamodel te beschrijven en een runtime
47+
die queries tegen dat model uitvoert. Het is in 2012 ontwikkeld bij Facebook,
48+
dat worstelde met de datavoorziening van zijn mobiele apps, en in 2015 open
49+
source gemaakt. Sinds eind 2018 wordt de specificatie beheerd door de
50+
onafhankelijke [GraphQL Foundation](https://graphql.org/foundation/), onderdeel
51+
van de Linux Foundation. In september 2025 verscheen de
52+
[September 2025 Edition](https://graphql.org/blog/2025-09-08-september-edition/),
53+
de eerste nieuwe editie sinds oktober 2021.
54+
55+
## De bouwstenen
56+
57+
### Het schema
58+
59+
Het hart van elke GraphQL-API is het schema, geschreven in de Schema Definition
60+
Language (SDL). Het schema beschrijft welke types er bestaan, hoe ze samenhangen
61+
en welke queries mogelijk zijn. Een sterk vereenvoudigd voorbeeld, losjes
62+
gebaseerd op het API-register:
63+
64+
```graphql
65+
type Organisatie {
66+
id: ID!
67+
naam: String!
68+
apis: [Api!]!
69+
}
70+
71+
type Api {
72+
id: ID!
73+
titel: String!
74+
versie: String!
75+
organisatie: Organisatie!
76+
}
77+
78+
type Query {
79+
organisatie(id: ID!): Organisatie
80+
organisaties: [Organisatie!]!
81+
apis: [Api!]!
82+
}
83+
```
84+
85+
Het uitroepteken markeert verplichte (non-nullable) velden. Let op de relaties:
86+
een `Organisatie` heeft `apis`, en een `Api` verwijst terug naar zijn
87+
`organisatie`. Het schema vormt zo een _graph_ van samenhangende types; vandaar
88+
de naam.
89+
90+
### Queries
91+
92+
De client stelt een query samen die qua vorm het gewenste antwoord spiegelt:
93+
94+
```graphql
95+
{
96+
organisatie(id: "min-bzk") {
97+
naam
98+
apis {
99+
titel
100+
versie
101+
}
102+
}
103+
}
104+
```
105+
106+
De server antwoordt met exact de gevraagde velden, niets meer en niets minder:
107+
108+
```json
109+
{
110+
"data": {
111+
"organisatie": {
112+
"naam": "Ministerie van BZK",
113+
"apis": [
114+
{ "titel": "Adressenregister API", "versie": "2.1.0" },
115+
{ "titel": "Organisaties API", "versie": "1.0.3" }
116+
]
117+
}
118+
}
119+
}
120+
```
121+
122+
### Variabelen
123+
124+
In de praktijk schrijven clients geen letterlijke waarden in de query, maar
125+
benoemde operaties met variabelen:
126+
127+
```graphql
128+
query ApisVanOrganisatie($id: ID!) {
129+
organisatie(id: $id) {
130+
naam
131+
apis {
132+
titel
133+
}
134+
}
135+
}
136+
```
137+
138+
```json
139+
{ "id": "min-bzk" }
140+
```
141+
142+
De query wordt daarmee een herbruikbaar, valideerbaar document dat los van de
143+
invoer bestaat. Onthoud deze vorm: in deel 2 zien we dat zulke benoemde
144+
documenten de basis vormen voor beheersmaatregelen zoals persisted queries.
145+
146+
### Mutations en subscriptions
147+
148+
Schrijfoperaties heten _mutations_. Ze zijn in het schema expliciet gescheiden
149+
van queries en geven, net als queries, precies de gevraagde velden terug:
150+
151+
```graphql
152+
mutation {
153+
registreerApi(
154+
input: { titel: "Vergunningen API", organisatieId: "gm0363" }
155+
) {
156+
id
157+
titel
158+
}
159+
}
160+
```
161+
162+
Daarnaast kent GraphQL _subscriptions_: de server pusht wijzigingen naar de
163+
client zodra die zich voordoen, een patroon dat aansluit bij
164+
[Event Driven Architecture](/kennisbank/api-ontwikkeling/architectuur/eda). In
165+
de rest van deze serie richten we ons op het bevragen van data; het ontwerp van
166+
mutations en subscriptions laten we verder buiten beschouwing.
167+
168+
### Resolvers
169+
170+
Aan de serverkant wordt elk veld ingevuld door een _resolver_: een functie die
171+
weet hoe de waarde van dat ene veld opgehaald moet worden. Hoe de data achter de
172+
schermen is opgeslagen (één database, meerdere services, een externe API) is
173+
voor de client onzichtbaar. Dat maakt GraphQL ook geschikt als
174+
_orkestratielaag_: een schema dat gegevens uit meerdere bestaande API's
175+
combineert en in samenhang bevraagbaar maakt, zonder die bronnen te vervangen.
176+
Op dat patroon komen we in deel 4 terug.
177+
178+
### Introspectie
179+
180+
Een GraphQL-API is zelfbeschrijvend: via een standaard introspectie-query kan
181+
elke client het volledige schema opvragen. Daarop bouwt een rijk ecosysteem van
182+
tooling, zoals interactieve explorers (GraphiQL), automatische documentatie en
183+
codegeneratie voor clients.
184+
185+
## Dezelfde vraag in REST
186+
187+
Hoe zou de bovenstaande informatiebehoefte er met een klassieke REST-API
188+
uitzien? Waarschijnlijk ongeveer zo:
189+
190+
```http
191+
GET /organisaties/min-bzk
192+
GET /organisaties/min-bzk/apis
193+
```
194+
195+
De eerste call levert de volledige organisatie-representatie op, inclusief
196+
adresgegevens, contactinformatie en andere velden die we in dit scenario niet
197+
nodig hebben. Dat heet _overfetching_. Levert de tweede call alleen
198+
samenvattingen op, dan is per API mogelijk nog een extra call nodig voor de
199+
details: _underfetching_, met meerdere roundtrips tot gevolg.
200+
201+
Dit is het probleem waarvoor GraphQL is ontworpen. In één request, in één
202+
roundtrip, precies de benodigde data, ongeacht hoeveel types de vraag raakt.
203+
Voor Facebook, met trage mobiele netwerken en een nieuws-feed vol diep geneste,
204+
onderling verbonden data, was dat de bestaansreden.
205+
206+
REST kan hetzelfde bereiken, met zorgvuldig ontworpen resources, `fields`- of
207+
`expand`-parameters, of een specifiek op een scherm toegesneden endpoint. Het
208+
verschil is dat GraphQL deze flexibiliteit _generiek_ biedt, terwijl je haar in
209+
REST per geval ontwerpt. Op die afweging komen we in deel 2 uitgebreid terug.
210+
211+
## Een ander paradigma, geen "betere REST"
212+
213+
Het is verleidelijk GraphQL te zien als "REST, maar dan handiger". Dat doet
214+
beide tekort. Het verschil wordt zichtbaar zodra je naar het HTTP-verkeer kijkt.
215+
Een minimale variant van de benoemde operatie uit de paragraaf over variabelen
216+
gaat zo over de lijn:
217+
218+
```http
219+
POST /graphql HTTP/1.1
220+
Content-Type: application/json
221+
222+
{
223+
"query": "query Naam($id: ID!) { organisatie(id: $id) { naam } }",
224+
"variables": { "id": "min-bzk" }
225+
}
226+
```
227+
228+
Eén endpoint, vrijwel altijd `POST`, en de eigenlijke vraag zit in de body. Voor
229+
het netwerk is elk GraphQL-request identiek; wat er gevraagd wordt, is alleen
230+
zichtbaar voor wie de body parseert. Zet de twee modellen naast elkaar:
231+
232+
- **REST** modelleert _resources_ en leunt op de semantiek van HTTP: werkwoorden
233+
(`GET`, `POST`, `PUT`, `DELETE`), statuscodes, unieke URI's per resource,
234+
cache-headers en content negotiation. Het netwerk "begrijpt" een REST-API: een
235+
cache, proxy of loadbalancer kan zinvol reageren op wat er langskomt.
236+
- **GraphQL** modelleert een _graph_ van types en gebruikt HTTP vooral als
237+
transport. Vrijwel al het verkeer gaat via één endpoint (meestal
238+
`POST /graphql`), antwoorden komen doorgaans terug met status `200 OK`, ook
239+
als er iets misging, en fouten staan als data in de responsebody.
240+
241+
In onze eerdere blogpost over
242+
[OpenAPI 3.1](/blog/2025/07/10/openapi-31-in-zicht) constateerden we dit al:
243+
GraphQL gebruikt HTTP wel als protocol, maar volgt niet het HTTP-model waarop
244+
specificaties als
245+
[OpenAPI](/kennisbank/api-ontwikkeling/standaarden/openapi-specification) zijn
246+
gebaseerd. De
247+
[GraphQL over HTTP-specificatie](https://graphql.github.io/graphql-over-http/),
248+
die vastlegt hoe GraphQL-verkeer over HTTP hoort te lopen, is op het moment van
249+
schrijven (medio 2026) nog een working draft; het transportgedrag ligt formeel
250+
dus nog niet vast.
251+
252+
Dit paradigmaverschil is de rode draad van deze serie. Vrijwel elk voordeel én
253+
vrijwel elke uitdaging van GraphQL is erop terug te voeren: wat je wint aan
254+
flexibiliteit in de bevraging, moet je elders opnieuw organiseren. Denk aan
255+
caching, autorisatie en beheersing van de belasting.
256+
257+
## De rest van deze serie
258+
259+
<!-- TODO: bij publicatie van deel 2, 3 en 4 hier telkens de link naar het
260+
verschenen deel toevoegen -->
261+
262+
In de komende delen gaan we de diepte in:
263+
264+
- **Deel 2** behandelt de kernbelofte van GraphQL (flexibel bevragen als
265+
oplossing voor over- en underfetching) en de prijs die daar tegenover staat:
266+
onvoorspelbare performance en een groter aanvalsoppervlak, en hoe je daar
267+
limieten aan stelt.
268+
- **Deel 3** duikt in de praktijk van schema-ontwerp: paginering, filtering,
269+
union types, custom scalars, autorisatie en content negotiation.
270+
- **Deel 4** brengt alles samen in een afwegingskader: wanneer is GraphQL een
271+
logische keuze, en wanneer ben je met REST beter af, zeker binnen de context
272+
van de Nederlandse overheid en de ADR.
273+
274+
Een compacte referentie over GraphQL, met de status binnen de overheid en de
275+
belangrijkste specificaties, staat in de
276+
[kennisbank](/kennisbank/api-ontwikkeling/standaarden/graphql).

0 commit comments

Comments
 (0)