Ga naar hoofdinhoud

JSON, REST & clientverzoeken

Tot hier ging het over HTTP als protocol: de vorm van een request en een response. Deze pagina gaat over de manier waarop het web dat protocol in de praktijk gebruikt: JSON als taal van de body, en REST als afspraak over hoe je URL's en methoden combineert.

JSON​

JSON (JavaScript Object Notation) is het standaardformaat voor gegevens in API's. Het is leesbaar voor mensen, eenduidig voor machines, en elke programmeertaal kan het lezen.

{
"id": 42,
"naam": "Robin",
"actief": true,
"score": 17.5,
"rollen": ["student", "beheerder"],
"adres": {
"stad": "Antwerpen",
"postcode": "2000"
},
"afgestudeerd": null
}
TypeSchrijfwijzeLet op
String"tekst"Altijd dubbele aanhalingstekens
Getal42, 17.5Geen aanhalingstekens, punt als decimaalteken
Booleantrue, falseKleine letters
NullnullNiet NULL of nil
Array[1, 2, 3]Volgorde telt
Object{"sleutel": "waarde"}Sleutels zijn altijd strings
De drie fouten die JSON ongeldig maken
  1. Enkele aanhalingstekens: {'naam': 'Robin'} is geen JSON.
  2. Een komma na het laatste element: {"a": 1,}.
  3. Commentaar toevoegen: JSON kent geen //.

Levert de server 400 Bad Request op je body, plak ze dan even in de console met JSON.parse(...) of in een validator. Meestal is het een van deze drie.

Een JSON-body zonder de header Content-Type: application/json is vragen om problemen. Zie HTTP-headers.

REST​

REST is geen protocol maar een stijl: een verzameling afspraken die zegt hoe je HTTP gebruikt zoals het bedoeld is. Een API die zich eraan houdt, kan je grotendeels raden zonder de documentatie te lezen. Dat is meteen het hele punt.

URL's zijn zelfstandige naamwoorden​

Een pad benoemt een ding, geen actie. De actie zit al in de methode.

Zoals het hoortZoals het niet hoort
GET /gebruikersGET /getGebruikers
POST /gebruikersPOST /maakGebruikerAan
DELETE /gebruikers/42POST /verwijderGebruiker?id=42
GET /gebruikers/42/bestellingenGET /haalBestellingenVanGebruiker?id=42

Dezelfde vijf handelingen, altijd​

Wat je wilMethodePadVerwachte statuscode
Alle gebruikers opvragenGET/gebruikers200 OK
Eén gebruiker opvragenGET/gebruikers/42200 OK of 404
Een gebruiker aanmakenPOST/gebruikers201 Created
Een gebruiker volledig vervangenPUT/gebruikers/42200 OK
Eén veld aanpassenPATCH/gebruikers/42200 OK
Een gebruiker verwijderenDELETE/gebruikers/42204 No Content

Merk het patroon op: de collectie (/gebruikers) voor lijsten en nieuwe items, het item (/gebruikers/42) voor alles wat over één ding gaat.

Query-parameters horen bij de lijst, niet bij de actie​

GET /producten?categorie=laptops&max_prijs=1000&sorteer=prijs&pagina=2

Filteren, sorteren en pagineren: dat is waar query-parameters voor dienen. Het id van één product hoort in het pad (/producten/42), niet in een parameter.

Alles samen in één schema. Merk op dat de collectie maar twee methoden kent en het item vier: je kan een lijst niet "vervangen" of "verwijderen", en je kan niet iets nieuws aanmaken ónder een bestaand item.

Schema van een REST-resource: de collectie /gebruikers met GET en POST, en daaronder het item /gebruikers/42 met GET, PUT, PATCH en DELETE, telkens met de verwachte statuscodeCOLLECTIE/gebruikersGET200 OKalle gebruikers, als lijstPOST201 Creatednieuwe gebruiker; adres in de Location-header?rol=admin&pagina=2filteren en pagineren: in de query, niet in het padéén item, aangeduid met zijn idITEM/gebruikers/42GET200 OKdeze gebruiker; 404 als het id niet bestaatPUT200 OKvolledig vervangen door wat je meestuurtPATCH200 OKenkel de velden die je meestuurtDELETE204 No Contentverwijderd; niets terug te sturen

Een verzoek opbouwen: drie clients, één request​

Wat je ook gebruikt, er gaat exact hetzelfde over de lijn. De server ziet geen verschil.

curl​

curl -X POST https://jsonplaceholder.typicode.com/posts \
-H "Content-Type: application/json" \
-d '{"title": "Mijn post", "body": "Inhoud", "userId": 1}'

fetch() in de browser​

const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title: 'Mijn post', body: 'Inhoud', userId: 1 }),
});

const data = await response.json();
console.log(response.status, data);

Postman​

Methode POST kiezen, de URL invullen, bij Headers Content-Type: application/json toevoegen, en bij Body → raw → JSON je gegevens plakken.

Naast elkaar gezet valt op hoe letterlijk die drie op elkaar lijken:

Onderdeelcurlfetch()Postman
Methode-X POSTmethod: 'POST'Keuzemenu
Headers-H "..."headers: { ... }Tabblad Headers
Body-d '...'body: JSON.stringify(...)Tabblad Body
ResultaatUitvoer in de terminalresponse.status, await response.json()Onderste paneel
response.ok is geen garantie

fetch() faalt enkel bij netwerkfouten, niet bij 404 of 500: die zijn geldige responses. Controleer dus altijd zelf de statuscode:

if (!response.ok) {
throw new Error(`Request mislukt met status ${response.status}`);
}

Alles samen ontleed​

Een volledig POST-request met de bijhorende response, met bij elk onderdeel de pagina waar het uitgelegd werd:

Request

POST /api/gebruikers HTTP/1.1 ← methode + pad + versie
Host: api.voorbeeld.be ← verplichte header
Content-Type: application/json ← formaat van de body
Content-Length: 47
Authorization: Bearer eyJhbGci... ← wie je bent, bij elk request opnieuw

{"naam": "Robin", "email": "r@ap.be"} ← de body, in JSON

Response

HTTP/1.1 201 Created ← gelukt, en er is iets aangemaakt
Content-Type: application/json ← formaat van het antwoord
Location: /api/gebruikers/5 ← waar de nieuwe bron staat

{"id": 5, "naam": "Robin", "email": "r@ap.be"}
OnderdeelUitgelegd in
POST, en waarom niet PUTHTTP-methoden
/api/gebruikersURI's en URL's
Host, Content-Type, Authorization, LocationHTTP-headers
201 CreatedStatuscodes
De JSON-bodydeze pagina
Twee API's om op te oefenen
  • jsonplaceholder.typicode.com – doet alsof: je POST krijgt netjes 201 en een id terug, maar er wordt niets bewaard.
  • httpbin.org – kaatst je request terug als JSON, inclusief je headers en je body. Ideaal om te controleren wat je nu écht verstuurde.

Test jezelf​

1. Welke aanroep past het best bij "verwijder bestelling 17"?

2. Je `fetch()` krijgt een `404` terug. Wat gebeurt er in je code?

3. Waarvoor gebruik je query-parameters in een REST-API?

Onthoud
  • JSON gebruikt dubbele aanhalingstekens, geen komma na het laatste element en geen commentaar; stuur altijd Content-Type: application/json mee.
  • REST gebruikt paden als zelfstandige naamwoorden en zet de actie in de methode.
  • De collectie (/gebruikers) dient voor lijsten en nieuwe items, het item (/gebruikers/42) voor alles wat over één ding gaat.
  • Query-parameters dienen om te filteren, sorteren en pagineren.
  • curl, fetch() en Postman bouwen exact hetzelfde request op; fetch() gooit geen fout bij 404 of 500.