skills/ls-api/SKILL.md
NL GOV API Design Rules (ADR): normatieve regels voor REST APIs: naming, versioning, problem+json, transport security, signing, encryption, geo, Spectral ADR-ruleset.
npx skillsauth add minbzk/logius-standaarden-plugin ls-apiInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
CONCEPT — Let op: Deze skill is geen officieel product van Logius. De beschrijvingen zijn informatieve samenvattingen — niet de officiële standaarden zelf. De definities op forumstandaardisatie.nl en Logius zijn altijd leidend. Overheidsorganisaties die generatieve AI inzetten dienen te voldoen aan het Overheidsbreed standpunt voor de inzet van generatieve AI. Zie DISCLAIMER.md en onze verantwoording.
Agent-instructie: Deze skill bevat de normatieve regels uit de NL GOV API Design Rules (ADR), verplicht onder 'pas-toe-of-leg-uit' van het Forum Standaardisatie. Voor de praktische bouw-flow (design-first met OAS-generator, validatie met don-checker, schema-register lookup, codegen) zie de don-tools skill in developer-overheid-nl/skills-developer-overheid-nl.
De API Design Rules (ADR) zijn de Nederlandse standaard voor het ontwerpen van RESTful APIs bij de overheid. Ze zijn verplicht onder het "pas-toe-of-leg-uit" regime van het Forum Standaardisatie. De standaard bevat concrete, toetsbare regels voor URI-ontwerp, HTTP-methoden, versiebeheer, beveiliging, foutafhandeling en meer.
De ADR levert herbruikbare headers en foutresponses op https://static.developer.overheid.nl/adr/components.yaml. Verwijs ernaar met externe $refs in plaats van ze inline te herdefiniëren — zo blijft je OAS consistent met de standaard en hoef je deze componenten niet zelf bij te houden. Beschikbaar: headers API-Version en Link; responses 400 (problem+json), 401, 403, 404, 204, 501.
paths:
/bieren/{id}:
get:
responses:
"200":
description: OK
headers:
API-Version:
$ref: 'https://static.developer.overheid.nl/adr/components.yaml#/headers/API-Version'
"404":
$ref: 'https://static.developer.overheid.nl/adr/components.yaml#/responses/404'
"400":
$ref: 'https://static.developer.overheid.nl/adr/components.yaml#/responses/400'
Let op:
components.yamlheeftheaders:enresponses:op rootniveau (geencomponents:-wrapper), dus de$ref-paden zijn#/headers/...en#/responses/....
De ADR kent twee publicatiekanalen (vergelijkbaar met W3C-standaarden):
gitdocumentatie.logius.nllogius-standaarden.github.io. De werkversie op GitHub Pages is de lopende ontwikkeling richting de volgende release. De ReSpec-configuratie toont daar nog '2.1.0' maar dit betreft werk-in-uitvoering.Modules hebben geen eigen vaststellingsproces — ze ontlenen hun status aan de standaard die ernaar verwijst. Als de ADR in een vastgestelde versie normatief naar een module verwijst, is die module daarmee ook vastgesteld. Zo is de Geospatial module v1.0.x normatief onderdeel van ADR v2.1.0 en daarmee vastgesteld. De inhoud van Transport Security is in ADR v2.1.0 ingebed als sectie 3.8 met eigen regels (/core/transport/*). De module v1.0 staat nog normatief vermeld in de leeswijzer van v2.1.0, maar de GitHub-repository is gearchiveerd.
| Repository | Beschrijving | Licentie | Vastgesteld | Draft | |-----------|-------------|--------|------------|-------| | API-Design-Rules | Hoofdspecificatie (ADR) | CC-BY-4.0 | v2.1.0 | Draft | | ADR-Beheermodel | Beheermodel voor de ADR standaard — gearchiveerd, vervangen door API-Standaarden-Beheermodel | CC-BY-4.0 | v1.0 | - | | API-Standaarden-Beheermodel | Overkoepelend beheermodel API-standaarden | CC-BY-4.0 | - | Draft | | API-mod-geospatial | Module: Geospatial (GeoJSON, CRS) — normatief in ADR v2.1.0 | CC-BY-4.0 | v1.0.3 | Draft | | API-mod-transport-security | Module: Transport Security — gearchiveerd; inhoud ingebed in ADR v2.1.0; normatief vermeld in leeswijzer; repo gearchiveerd | CC-BY-4.0 | - | - | | API-mod-signing | Module: HTTP Message Signing — draft | CC-BY-4.0 | - | Draft | | API-mod-encryption | Module: Encryption (JWE) — draft | CC-BY-4.0 | - | Draft | | api-linter-impactanalyse | Python tool: test Spectral regels tegen echte OpenAPI specs uit het API-register | Niet gespecificeerd | - | - | | zaakgericht-werken-api | API-specificatie voor zaakgericht werken | CC-BY-4.0 | - | - |
/mijn-documenten (niet /mijnDocumenten)?sortOrder=desc/api/v1/users (niet /api/v1/users/)/v1/resources (Let op: in de OAS moet dit op serverniveau worden gespecificeerd, niet in individuele paden. Dit om uit te sluiten dat één API meerdere major versies in verschillende paden heeft, wat verwarrend is. De linter controleert op aanwezigheid van major versie in server URL, niet in individuele paden.)_ (bijv. /_search)| Methode | Gebruik | Veilig | Idempotent | |---------|--------|--------|------------| | GET | Resource ophalen, nooit wijzigen | Ja | Ja | | POST | Subresource aanmaken in collectie | Nee | Nee | | PUT | Resource aanmaken of volledig vervangen | Nee | Ja | | PATCH | Gedeeltelijke update | Nee | Nee | | DELETE | Resource verwijderen | Nee | Ja |
/v1, /v2API-Version response header: 1.2.3info.versionGebruik application/problem+json (RFC 9457) voor foutresponses:
{
"type": "https://example.com/errors/insufficient-funds",
"title": "Insufficient Funds",
"status": 422,
"detail": "Your current balance is 30, but that costs 50.",
"instance": "/account/12345/transactions/abc"
}
Geen technische details (stack traces, interne hints) in foutmeldingen.
date-time velden (bijv. 2026-04-11T10:30:00+02:00)format: date wanneer alleen een datum nodig is (niet date-time)format voor properties die datum of tijd bevattendate-time-ensure-timezone, specify-format-for-date-and-time, time-without-timezone, use-date-instead-of-datetime)/users, /orders/users/{id}/openapi.json (VERPLICHT); YAML (/openapi.yaml) is OPTIONEELinfo.contact met name, email, url) wordt sterk aanbevolen voor publieke APIs (ADR /core/doc-openapi-contact: SHOULD); de Spectral linter dwingt deze velden af als error voor publieke APIs. Verwijs naar het verantwoordelijke team, niet naar een individu of algemene helpdesk (info@…); gebruik als url bij voorkeur een issuetracker i.p.v. een homepageLet op: De Transport Security module werd als aparte module normatief verwezen door ADR v2.0.0. Vanaf ADR v2.1.0 zijn de transport-security-eisen ingebed in de hoofdspecificatie (sectie 3.8, regels
/core/transport/*) en is de repository gearchiveerd. De module v1.0 staat nog normatief vermeld in de leeswijzer van ADR v2.1.0.
Alle verbindingen MOETEN TLS gebruiken (wettelijk verplicht). Volg de laatste NCSC-richtlijnen.
Verplichte security headers in alle API-responses:
| Header | Doel |
|--------|------|
| Cache-Control: no-store | Voorkom caching van gevoelige data |
| Content-Security-Policy: frame-ancestors 'none' | Clickjacking bescherming |
| Content-Type: application/json | Specificeer content type |
| Strict-Transport-Security | Vereis HTTPS |
| X-Content-Type-Options: nosniff | Voorkom MIME sniffing |
| X-Frame-Options: DENY | Clickjacking bescherming |
| Access-Control-Allow-Origin | CORS beleid |
Normatief onderdeel van ADR v2.1.0. Verplicht bij geospatiale data. Regelt GeoJSON encodering, bounding box filtering, en coördinaatsystemen (CRS). Zie de vastgestelde versie.
Let op: Deze module is nog in concept (draft) en is nog niet goedgekeurd door het Technisch Overleg. De inhoud kan nog wijzigen.
Voor end-to-end berichtintegriteit en authenticiteit. Gebruikt JAdES detached signatures met RSASSA-PSS (PS256), minimaal 256 bits. Signatures in Payload-Signature en Message-Signature HTTP headers. OpenAPI representatie met format: jws-compact-detached.
Let op: Deze module is nog in concept (draft) en is nog niet goedgekeurd door het Technisch Overleg. De inhoud kan nog wijzigen.
Voor end-to-end versleuteling van request/response payloads wanneer transport-level encryptie niet voldoende is (bijv. bij niet-vertrouwde intermediairs).
from fastapi import FastAPI, Query, Request, HTTPException
from fastapi.responses import JSONResponse
from pydantic import BaseModel
from datetime import date
app = FastAPI(
openapi_url="/v1/openapi.json",
title="Zaakgericht Werken API",
version="1.2.0",
contact={"name": "API Team", "url": "https://github.com/example/api/issues", "email": "[email protected]"},
servers=[{"url": "https://api.example.com"}],
)
class Zaak(BaseModel):
id: str
zaaktype: str
omschrijving: str
startdatum: date
status: str
@app.middleware("http")
async def add_adr_headers(request: Request, call_next):
response = await call_next(request)
response.headers["API-Version"] = "1.2.0"
response.headers["Content-Type"] = "application/json"
response.headers["Cache-Control"] = "no-store"
response.headers["Strict-Transport-Security"] = "max-age=31536000"
response.headers["X-Content-Type-Options"] = "nosniff"
response.headers["X-Frame-Options"] = "DENY"
response.headers["Content-Security-Policy"] = "frame-ancestors 'none'"
return response
@app.get("/v1/zaken", response_model=list[Zaak])
async def list_zaken(
status: str | None = Query(None, description="Filter op status"),
startdatum__gte: date | None = Query(None, alias="startdatumGte", description="Vanaf datum"),
page: int = Query(1, ge=1),
page_size: int = Query(20, ge=1, le=100, alias="pageSize"),
):
"""Haal zaken op met paginering en filtering (ADR-compliant)."""
# Paginering met standaard page_size=20, max 100
offset = (page - 1) * page_size
return db.query_zaken(status=status, since=startdatum__gte, offset=offset, limit=page_size)
@app.exception_handler(HTTPException)
async def problem_json_handler(request: Request, exc: HTTPException):
"""RFC 9457 problem+json (verplicht per ADR)."""
return JSONResponse(
status_code=exc.status_code,
content={
"type": f"https://api.example.com/errors/{exc.status_code}",
"title": exc.detail if isinstance(exc.detail, str) else "Error",
"status": exc.status_code,
"instance": str(request.url),
},
media_type="application/problem+json",
)
/openapi.json (VERPLICHT); /openapi.yaml is optioneel/v1)API-Version response headerinfo.versionapplication/problem+json voor foutresponsesOpenAPI-specs worden tegen de ADR-ruleset gevalideerd. Er zijn twee varianten van de Spectral-ruleset in omloop:
https://static.developer.overheid.nl/adr/ruleset.yaml) — 11 regelslogius-standaarden/API-Design-Rules, media/linter.yaml) — 22 regels, met aanvullende checks voor naamgeving, contactinformatie, datum/tijd en foutafhandelingVoor de praktische uitvoering (CLI-commando's voor de DON Checker en Spectral, CI-integratie, ruleset inspecteren) zie de don-tools skill in developer-overheid-nl/skills-developer-overheid-nl.
Kern (DON-naam / GitHub-naam):
include-major-version-in-uri / nlgov:include-major-version-in-uri - Major versie in URI padpaths-no-trailing-slash / nlgov:paths-no-trailing-slash - Geen trailing slashespaths-kebab-case / nlgov:paths-kebab-case - Kebab-case padsegmentenhttp-methods / nlgov:http-methods - Alleen standaard HTTP methodenmissing-version-header / nlgov:missing-version-header - Version header in 2xx/3xx responsesuse-problem-schema / nlgov:use-problem-schema - Problem+json voor foutenAlleen in de GitHub-versie (22 regels totaal, 11 extra t.o.v. DON):
nlgov:query-keys-camel-case - camelCase query parametersnlgov:info-contact-fields-exist - Contactinformatie velden aanweziginfo-contact - Contactobject aanwezig (zonder nlgov: prefix)nlgov:semver - Semantic versioning formaatnlgov:openapi-root-exists - OpenAPI root object aanwezigoas3-api-servers - Servers array aanwezig (built-in regel op error gezet)nlgov:problem-schema-members - Verplichte velden in problem+json schema (RFC 9457)nlgov:date-time-ensure-timezone - Datum/tijd velden met timezonenlgov:time-without-timezone - Detecteert time format zonder timezonenlgov:specify-format-for-date-and-time - Verplicht format voor datum/tijd propertiesnlgov:use-date-instead-of-datetime - Gebruik date i.p.v. date-time waar geen tijd nodig isZie reference.md voor Express.js/Go voorbeelden, impact analyse tool, en repo-exploratie commando's. Zie conflicts.md voor bekende discrepanties tussen GitHub-tags en gepubliceerde versies.
development
Overzicht van Logius standaarden voor de Nederlandse overheid. Routeert naar sub-skills (Digikoppeling, API Design Rules, OAuth, FSC, BOMOS, etc.) of geeft hulp bij interoperabiliteitsvragen.
development
Logius publicatieworkflow voor standaardenrepos: ReSpec, GitHub Actions, markdownlint, WCAG/a11y, Muffet linkvalidatie, tech radar. Niet voor API of code linting.
development
NL GOV CloudEvents profiel voor notificatieservices: abonnementen, webhooks, pub/sub tussen overheidsorganisaties.
data-ai
Logboek Dataverwerkingen voor AVG/GDPR-transparantie. NEN 7513, OpenTelemetry/OTLP, dpl.core, verwerkingenlogging in overheidssystemen.