aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Webontwikkeling

REST API Best Practices: ontwerpgids

Een goed ontworpen API is een plezier om te gebruiken; een slecht ontworpen API wordt een puzzel die je bij elke aanvraag opnieuw moet oplossen. In dit artikel verzamel ik de REST API best practices die echt helpen in de dagelijkse ontwikkeling — van het benoemen van resources en HTTP-methoden tot statuscodes en versiebeheer. Het doel is een consistente, voorspelbare interface die andere ontwikkelaars (en jijzelf, over zes maanden) kunnen raden zonder de documentatie te openen.

Resources benoemen: zelfstandige naamwoorden, geen werkwoorden

Het kernidee van REST is om je systeem rond resources te modelleren. Endpoint-paden moeten zelfstandige naamwoorden bevatten, geen werkwoorden, en meervoud gebruiken voor collecties. De actie wordt uitgedrukt door de HTTP-methode; die in het pad zetten is overbodig.

  • Goed: GET /users, GET /users/42, POST /users
  • Slecht: GET /getUsers, POST /createUser, GET /user/list

Toon bij geneste resources de relatie in het pad: de bestellingen van een gebruiker lezen natuurlijk als GET /users/42/orders. Maar nest niet meer dan ongeveer twee niveaus diep; paden als /users/42/orders/7/items/3/reviews worden moeilijk te onderhouden. Bied in plaats daarvan directe toegang tot de sub-resource: GET /order-items/3. Gebruik kleine letters en koppeltekens in URL's (/order-items), en vermijd underscores of camelCase.

Gebruik HTTP-methoden volgens hun betekenis

Elke methode heeft een expliciet contract, en dat respecteren laat tussenliggende lagen (caches, proxy's, browsers) zich correct gedragen.

  • GET — leest een resource, zonder neveneffecten (veilig en idempotent).
  • POST — maakt een nieuwe resource; niet idempotent (twee keer aanroepen maakt twee records).
  • PUT — vervangt de volledige resource; idempotent (dezelfde aanvraag herhalen verandert het resultaat niet).
  • PATCH — werkt een deel van de resource bij.
  • DELETE — verwijdert de resource; idempotent.

Praktische regel: GET mag nooit gegevens wijzigen. Een "verwijder"-actie op een endpoint als GET /users/42/delete zetten komt vaak voor maar is fout, want een browser-prefetch of een crawler kan het record ongemerkt verwijderen. Geef de voorkeur aan PUT voor een volledige update en PATCH voor een gedeeltelijke.

Geef de juiste statuscodes terug

De statuscode is het eerste signaal van wat er gebeurd is, nog voordat de responsbody is gelezen. Altijd 200 OK teruggeven en {"success": false} in de body schrijven, verblindt de client. De codes die je het meest zult gebruiken:

  • 200 OK — geslaagde GET/PUT/PATCH.
  • 201 Created — een resource is aangemaakt via POST; geef het adres terug in de Location-header.
  • 204 No Content — succes zonder body (meestal DELETE).
  • 400 Bad Request — de aanvraag is onjuist of slaagde niet voor de validatie.
  • 401 Unauthorized — niet geauthenticeerd; 403 Forbidden — geauthenticeerd maar geen toestemming.
  • 404 Not Found — de resource bestaat niet.
  • 409 Conflict — een conflict (bijv. een dubbel e-mailadres).
  • 422 Unprocessable Entity — syntaxis is geldig maar semantische validatie mislukte (veel frameworks gebruiken dit voor validatiefouten).
  • 429 Too Many Requests — rate limit overschreden.
  • 500 Internal Server Error — een onverwachte fout aan de serverkant.

Gebruik het verschil tussen 401 en 403 correct: de eerste betekent "ik weet niet wie je bent", de tweede "ik weet wie je bent, maar je mag dit niet doen".

Consistente, machineleesbare fouten

Elke fout in dezelfde structuur teruggeven, laat de client één foutafhandelingsroutine schrijven. Lever een leesbare message, een stabiele machine-code en validatiedetails per veld:

HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json

{
  "error": {
    "code": "validation_failed",
    "message": "De ingediende gegevens zijn ongeldig.",
    "fields": {
      "email": ["Voer een geldig e-mailadres in."],
      "age": ["Moet 18 jaar of ouder zijn."]
    }
  }
}

Houd het veld code stabiel en taalonafhankelijk (validation_failed), en gebruik message voor tekst die je aan een gebruiker kunt tonen. Lek in productie nooit de interne details van 500-fouten (stack traces, SQL); geef in plaats daarvan een request_id terug zodat de gebruiker aan support kan worden gekoppeld.

Versiebeheer: verandering beheren zonder te breken

Vanaf het moment dat je API live is, breekt elke wijziging die de achterwaartse compatibiliteit verbreekt bestaande clients. Daarom moet een versiestrategie vooraf worden bepaald. De meest voorkomende en zichtbaarste aanpak is de versie in het pad te zetten:

GET /v1/users
GET /v2/users

Je kunt de versie ook in een header meegeven (Accept: application/vnd.api+json; version=2); dit wordt als "zuiverder" beschouwd maar is moeilijker te ontdekken en te testen. Voor de meeste teams is URL-gebaseerd versiebeheer praktisch en duidelijk. Het kernprincipe: een veld toevoegen is meestal niet brekend, maar een veld verwijderen, hernoemen of het type ervan wijzigen is brekend en vereist een nieuwe versie. Publiceer een afbouwschema (deprecation) voor oude versies.

Lijst-endpoints: paginering, filteren, sorteren

Een collectie ongewijzigd teruggeven werkt voor kleine datasets, maar naarmate de tabel groeit, overweldigt het zowel server als client. Voeg paginering vanaf het begin toe aan lijst-endpoints. Er zijn twee veelgebruikte benaderingen:

  • Op offset: GET /users?page=3&per_page=20 — eenvoudig, laat je naar een paginanummer springen; maar het schuift weg als gegevens vaak veranderen.
  • Op cursor: GET /users?limit=20&cursor=eyJpZCI6MTQ0fQ — stabieler en beter presterend op grote, vaak veranderende datasets.

Druk filteren en sorteren uit met query-parameters: GET /users?status=active&sort=-created_at. Een voorafgaand - in de sortering is een gangbare conventie voor aflopende volgorde. Het totale aantal en de informatie over de volgende pagina teruggeven in een meta-blok maakt het navigeren voor de client eenvoudiger.

Nog enkele principes

  • Overal HTTPS: een API die tokens en persoonsgegevens vervoert, mag alleen over TLS draaien.
  • JSON-consistentie: houd je aan één stijl voor veldnamen (snake_case of camelCase) en wijzig die niet door de API heen.
  • ISO 8601 en UTC voor datums: het formaat 2026-06-27T14:30:00Z verwijdert dubbelzinnigheid.
  • Documentatie: publiceer een machineleesbaar schema met OpenAPI (Swagger), wat je zowel documentatie als generatie van clientcode geeft.
  • Rate limiting en authenticatie: voeg rate limiting toe om misbruik te voorkomen en meld de status met de juiste headers.

Veelgestelde vragen

Moet ik PUT of PATCH gebruiken?

Gebruik PUT wanneer je de volledige resource verstuurt en vervangt; gebruik PATCH wanneer je alleen de paar velden verstuurt die veranderen. PUT is idempotent: dezelfde volledige body herhaaldelijk versturen verandert het resultaat niet. PATCH is voor gedeeltelijke updates, en de body bevat alleen de te wijzigen velden.

Moet ik de versie in de URL of in een header houden?

Beide zijn geldig. URL-gebaseerd versiebeheer (/v1/...) is de keuze van de meeste teams omdat het makkelijk te ontdekken en in een browser te testen is. Header-gebaseerd versiebeheer ligt dichter bij de REST-zuiverheid maar is omslachtiger qua tooling-ondersteuning en zichtbaarheid. Zolang je consistent bent, zijn beide correct.

Kan ik niet gewoon voor alles 200 teruggeven en fouten in de body signaleren?

Nee. HTTP-statuscodes bestaan juist hiervoor; cachelagen, proxy's en clientbibliotheken handelen ernaar. 4xx/5xx voor fouten gebruiken laat de client de juiste beslissing nemen zonder de responsbody te parsen, en het verbetert de observeerbaarheid.

Wil je je API vanaf nul ontwerpen of je bestaande endpoints naar de standaard tillen? Van resource-modellering tot versiebeheer en documentatie kan ik je helpen een nette, consistente REST-interface te bouwen. Neem contact op en laten we de API van je project samen versterken.

Bu kategorideki tüm yazılar →

Devamı için