API strategie voor de Nederlandse overheid

Consultatieversie

Geonovum Handreiking
Consultatieversie

Deze versie:
https://docs.geostandaarden.nl/api/cv-hr-API-Strategie-20190213/
Laatst gepubliceerde versie:
https://docs.geostandaarden.nl/api/API-Strategie/
Laatste werkversie:
https://geonovum.github.io/KP-APIs/
Redacteurs:
Frank Terpstra, Geonovum
Jan van Gelder, Geonovum
Auteurs:
Lancelot Schellevis, Forum Standaardisatie
Friso Penninga, Geonovum
Matthias Snoei, Swis
Jasper Roes, Het Kadaster
Emile van de Maas
Doe mee:
GitHub geonovum/KP-APIs
Dien een melding in
Revisiehistorie
Pull requests
Rechtenbeleid:

Samenvatting

Dit document beschrijft een API strategie voor de Nederlandse overheid.

Status van dit document

Deze paragraaf beschrijft de status van dit document ten tijde van publicatie. Het is mogelijk dat er actuelere versies van dit document bestaan. Een lijst van Geonovum publicaties en de laatste gepubliceerde versie van dit document zijn te vinden op https://www.geonovum.nl/geo-standaarden/alle-standaarden.

Dit is een door de werkgroep goedgekeurde consultatieversie. Commentaar over dit document kan gestuurd worden naar geo-standaarden@geonovum.nl.

1. Inleiding

Dit hoofdstuk geeft een inleiding op de Nederlandse API strategie

1.1 Status van de API strategie

1.2 Leeswijzer

Dit document bevat twee delen, waarbij het eerste deel "niet-technisch" en het tweede deel "technisch" van aard is. In het eerste deel zitten de hoofdstukken Communicatie en Beleid en Gebruikerswensen.

Het tweede deel bevat de hoofdstukken API designrules, Beveiliging en Architectuur, waarin een technische uitwerking van de eerste twee hoofdstukken staat.

2. Communicatie en Beleid

Dit hoofdstuk is een Management samenvatting voor managers van overheden en partijen die met de overheid te maken hebben. Dit hoofdstuk beschrijft:
- waarom wil je API's gebruiken.
- Hoe relateert het gebruik van API's aan de maatschappelijke discussie.
- Wat is de uitwerking voor inclusiviteit regie op gegevens veiligheid.
- Uitgelegd en verduidelijkt met voorbeelden

2.1 Application Programming Interfaces, wat zijn het en waarom hierop in te zetten

Dit hoofdstuk heeft als doel om voor het beleid- en managementniveau te duiden wat API’s zijn en wat het belang ervan is. Het geeft inzicht in de mogelijkheden van API’s en waarom het voor de overheid van meerwaarde is om strategisch om te gaan met het aanbieden van API’s.

2.2 De rol van API’s in de platform economie

Online platformen nemen een steeds grotere rol in binnen onze samenleving. Zowel als het gaat om sociale interactie als wanneer het gaat om financiële transacties. Het is een organisatievorm die in toenemende mate aan belang wint en hele sectoren kan transformeren. Deze platformen zorgen ervoor dat personen en diensten elkaar makkelijk kunnen vinden, waardoor er nieuwe verbindingen tussen vele (onbekende) partijen ontstaan en ruimte ontstaat voor innovatie. Voor allerhande problemen en toepassingen zijn er dan ook steeds meer programma’s en app’s die je helpen. Bekende voorbeelden zijn Facebook, Google, Amazon en Airbnb, maar ook Adyen en BOL zijn platformen waar mensen en/of diensten elkaar vinden om transacties uit te voeren. Deze platformen zijn bovendien in staat om informatie snel en eenvoudig uit te wisselen en systemen efficiënt aan elkaar te koppelen. Deze koppelingen tussen systemen worden vaak via API’s gerealiseerd. Vanuit technisch perspectief zijn het dan ook API’s die ervoor hebben gezorgd dat deze platformen zo wendbaar zijn, makkelijk kunnen opschalen en dienstverlening centraal kunnen stellen. Hierdoor zijn ze in staat om snel nieuwe diensten uit te rollen en binnen enkele jaren uit te groeien tot organisaties die miljoenen mensen bereiken. Los van de discussie wat de impact is van deze platformen op onze samenleving, kan de overheid leren van de technieken die ze gebruiken om verschillende online diensten, bronnen en (basis)registraties beter te ontsluiten en met elkaar te laten samenwerken – via API’s.

2.3 Wat is een API

Een Application Programming Interface (API) is een combinatie van technische bestanden, documentatie en andere ondersteuning die helpen bij het aanroepen van externe applicaties (Als het in deze API-strategie gaat over API’s dan bedoelen we daarmee RESTful API’s). Een API wordt gepubliceerd door een softwareontwikkelaar, zodat andere ontwikkelaars weten hoe de software te koppelen aan de eigen software. Zodoende kunnen twee applicaties rechtstreeks en online met elkaar communiceren. Het is daarmee geen standaard, maar eerder een handleiding die kan worden gebruikt voor een machine tot machine koppeling. Met name daar waar veel digitale diensten met elkaar samenwerken en informatie realtime op een makkelijke en toegankelijke manier willen delen zijn API’s zeer geschikt. De belangrijke eigenschappen van moderne API’s zijn:

API’s kunnen gezien worden als ‘proven technology’, er is veel kennis over en ervaring mee in de markt. Berichten uitwisselen via API’s is niet perse onveiliger of veiliger dan hoe de overheid op dit moment haar berichtenuitwisseling organiseert. Het gebruik van API’s beperkt zich daarmee niet alleen tot open data, maar kan juist ook goed worden ingezet voor meer gevoelige / gesloten data.

2.4 Achtergrond

De opkomst van de API begon rond 2008. Tot die tijd was er op het internet maar één kanaal belangrijk: de menselijke gebruiker met een webbrowser. Sindsdien zijn er veel meer kanalen ontstaan via welke je als organisatie je diensten wil ontsluiten, bijvoorbeeld via mobiele devices, internet of things toepassingen, social media platforms en wearables. Ook de beweging naar cloud computing draagt bij aan het gebruik van API’s. Diensten worden steeds meer in de cloud aangeboden (en afgenomen), waarbij het nodig kan zijn om deze diensten met elkaar te integreren in andere producten.

Voor Nederlandse burgers en bedrijven betekenen de mogelijkheden die API’s bieden dat ze hetzelfde van de overheid verlangen als wat ze gewend zijn van (commerciële) platforms. Deze platforms zijn slim in het creëren van nieuwe diensten door het koppelen van verschillende API’s en kunnen makkelijk inspelen op nieuwe ontwikkelingen en goede dienstverlening. Daarnaast willen burgers informatie en diensten van de overheid snel en plaats-onafhankelijk gebruiken op alle kanalen die ze gewend zijn. De overheid biedt echter nog maar weinig API’s aan en maakt nog te gefragmenteerd gebruik van deze techniek. Omdat veel overheid-ICT is gebaseerd op principes uit de jaren ’90 en begin jaren ’00, kan de overheid onvoldoende meebewegen met technologische ontwikkelingen, nieuwe wetgeving en verwachtingen van haar burgers en bedrijven en raakt hierdoor achterop op technologisch vlak.

2.5 Belang voor de overheid

Verschillende ontwikkelingen en factoren maken het voor de overheid relevant om meer in te zetten op gegevensuitwisseling via API’s:

2.6 Developer First

De belangrijkste doelgroep van de digitale overheid die vaak wordt vergeten, is de programmeur. Vaak gaat het binnen de digitale overheid over betere dienstverlening voor burgers en bedrijven, maar bij het neerzetten van een goede ICT dienstverlening is de softwareontwikkelaar als doelgroep cruciaal. Het is immers de ontwikkelaar die de producten gaat bouwen en de data ontsluit en daarmee een cruciale rol inneemt als intermediair in de dienstverlening naar burgers en bedrijven. In de praktijk is er echter weinig aandacht om deze doelgroep goed te faciliteren.

Deze ‘developer first’ gedachte staat juist centraal binnen de online platformen. Daar wordt uitgegaan van een scheiding tussen data en processen. Voor een organisatie is het namelijk ondoenlijk om je te bemoeien met hoe de userinterface op alle kanalen en diensten eruit ziet. Terwijl het van toegevoegde waarde kan zijn om zijn unieke resources te ontsluiten zodat ontwikkelaars van andere platforms / organisaties hierop kunnen aansluiten en deze kunnen integreren. Als organisatie wil je er natuurlijk wel voor zorgen dat zoveel mogelijk gebruik gemaakt wordt van jouw API. Als anderen deze API hergebruiken krijg je namelijk ook hun gebruikers of klanten erbij en heb je een breder bereik. Hergebruik is te realiseren door het programmeurs van andere partijen zo makkelijk mogelijk te maken.

Er wordt dan ook voor gepleit om de ‘time to first call’ zo laag mogelijk te houden. Dit is de tijd die het duurt voordat je succesvol tussen systemen gegevens kan uitwisselen via de API. De regel is: hoe korter, hoe beter. Het grote bijkomende voordeel van deze gereduceerde complexiteit is ook dat hiermee wordt voorkomen dat er allerlei tussenoplossingen ontstaan en dat men iets zelf gaat bouwen. Door dergelijke tussenoplossingen ontstaat een complexer IT landschap en een verhoogd risico op ‘vendor lock-in’. Hoofdstuk 5 gaat in op hoe deze gebruikerswensen zijn te faciliteren.

2.7 Gegevens bevragen bij de bron

Binnen de overheid worden nog vaak databases gedupliceerd die vervolgens vanuit de bron worden gesynchroniseerd. Hierdoor worden gegevens op verschillende plekken bijgehouden, zowel in systemen van overheden als leveranciers. Het dupliceren en synchroniseren van gegevens brengt risico op fouten met zich mee, omdat op meerdere plekken dezelfde informatie onderhouden moet worden. Daarnaast is het ook lastiger om toezicht te houden op wie er toegang heeft tot deze gegevens en wanneer ze worden bevraagd. AVG compliancy is daarmee moeilijker en kostbaarder. Primaire bevraging bij de bron verdient dus de voorkeur voor het garanderen van de kwaliteit van data en zorgt voor meer transparantie en accountability. Door het inzetten van API’s wordt het makkelijker en minder kostbaar om de bron te bevragen, wat de noodzaak voor dupliceren vermindert. Daarnaast is het eenvoudiger om alleen die gegevens te leveren die echt nodig zijn voor een dienst en om de autorisatie hiervan bij de bron te beleggen.

2.8 Wat kan je zelf doen?

Om te bepalen wat een API gedreven informatie-uitwisseling kan betekenen voor je organisatie is een goede eerste stap om het visiedocument van de organisatie erbij te pakken. Kunnen de daarin gestelde doelstelling niet veel beter en makkelijker gerealiseerd worden als meer gebruik wordt gemaakt van gegevensuitwisseling via API’s?

Een goede twee stap is om te onderzoeken welke informatie je organisatie aanbiedt (denk bijvoorbeeld aan (basis)registraties), deze informatie is vaak ook informatie die gekoppeld is aan de primaire taken van een organisatie, en met API’s zijn deze mogelijk makkelijker te ontsluiten. De derde stap is dan om te kijken uit welke externe bronnen je informatie nodig hebt om de business doelstellingen te behalen. Kijk daarbij ook of de kwaliteit van de bronnen nu voldoende is. Dit kunnen zowel externe als interne bronnen zijn. Een vervolgstap is om te onderzoeken welke externe koppelingen met andere systemen (zowel interne als extern) er al zijn, hoe deze zijn ingericht en welke afspraken daar achter liggen en of het niet goedkoper en makkelijker kan via API’s.

Als hieruit voorkomt dat de organisatie veel te winnen heeft bij gegevensuitwisseling via API’s, dan is het vervolg van deze API strategie relevant om te bepalen hoe dat dan te doen. Het volgende hoofdstuk geeft een technische invulling aan hoe een organisatie zelf API’s kan aanbieden en welke voorwaarden, designprincipes en standaarden daarbij te hanteren.

2.9 Enkele voorbeelden

3. Gebruikerswensen

Inspelen op gebruikerswensen: dé sleutel tot gebruik

In dit hoofdstuk: Niet alleen wat je aanbiedt moet goed zijn maar vooral ook hoe je dat doet!
Onderwerpen:
- De gebruikers ervaring is erg belangrijk.
- Hoe krijg je partijen laagdrempelig snel echt aan de slag(niet alleen technisch)

3.1 Inleiding

Overheden bezitten kwalitatief hoogwaardige data en bieden deze aan via API’s. Vanuit het open data-perspectief maken overheden het hiermee mogelijk dat anderen -binnen én buiten de overheid- zinvolle toepassingen kunnen ontwikkelen, die maatschappelijke meerwaarde bieden. Maar de overheid gaat nog verder: bij initiatieven als Common Ground is het gebruik van API’s zelfs randvoorwaardelijk om werkprocessen zodanig in te richten, dat data altijd bij de bron bevraagd en gewijzigd kan worden. Een belangrijke succesfactor in deze ontwikkelingen is de mate waarin overheden erin slagen om drempels voor het gebruik van hun API’s weg te nemen. Om het gebruik zo laagdrempelig mogelijk te maken, is het essentieel dat er aandacht is voor de wensen van gebruikers. En die wensen liggen niet alleen op het “wat” (wat voor data krijg ik?), maar zeker ook op het “hoe” (hoe makkelijk kan ik aan de slag met deze API?). Bij de eerste kennismaking met de API moet de gebruiker verleidt worden om de API te gaan gebruiken en in alle volgende fases van gebruik (implementeren, in productie nemen en in productie houden) moet de gebruikerservaring zodanig zijn, dat de gebruiker geen enkele reden heeft om af te haken. Sterker nog: idealiter wordt de gebruiker zó enthousiast over de API en de bijbehorende ondersteuning, dat de gebruiker onderdeel wordt van de gebruikerscommunity en actief gaat bijdragen aan verdere ontwikkeling en promotie van die API. Merk op dat dit effect alleen bereikt kan worden, wanneer de totaalbeleving klopt: ook al is het product (de data) zelf nog zo goed, als de gebruikservaring belabberd is, dan zul je niet veel potentiële gebruikers verleiden om met je data zinvolle toepassingen te gaan ontwikkelen. En nog erger: gebruikers die tóch met de API aan de slag gaan, zullen de helpdesk van de aanbieder zwaar gaan belasten, de data mogelijk verkeerd gaan interpreteren en de ICT-infrastructuur onnodig zwaar belasten, wanneer zij slechts omslachtig (met veel API-calls) de gewenste gegevens kunnen krijgen.

3.2 Overkoepelende aanbeveling: biedt een goede ‘developer experience (DX)’

De belangrijkste aanbeveling aan aanbieders van API’s is om zich te richten op die gebruikservaring; op een goede ‘developer experience (DX)’. Goede DX komt voort uit stapeling van aandacht voor functionality (functionaliteit - wat moet de API doen?), voor usability (hoe bruikbaar is de API voor de developer?) en daar bovenop voor de experience (hoe voelt de developer zich als die de API gebruikt?). Dat laatste aspect -hoe voelt de developer zich- klinkt wellicht wat vaag, maar het is in essentie de optelsom van ervaringen in de interactie tussen een developer en een API aanbieder. Stel: een developer, Johan (26 jaar – ZZP-er), heeft moeite om een bepaalde API te vinden, vervolgens blijkt het registratieproces lastig en krijgt hij de API key pas een week later, daarna blijkt de documentatie in voor Johan deels onbegrijpelijk jargon geschreven (én is het ook nog eens een PDF van 352 pagina’s), dan heeft Johan meerdere calls nodig om de gewenste data te krijgen en uiteindelijk is data helemaal niet in het door Johan gewenst formaat. Elke kleine irritatie is op zichzelf niet onoverkomelijk, maar de optelsom maakt dat Johan concludeert: “Dit is niet te doen, ik zoek wel wat anders!”.

3.3 Gebruik: van ‘onboarding’ tot ‘in productie’

De zwakte van veel teksten over ‘developer experience’ is dat men zich vaak alleen richt op de use case van een technische developer die een API wil implementeren - denk aan Johan in de vorige paragraaf. Gebruik begint echter niet bij de poging tot implementatie; hier gaan nog stappen aan vooraf. Johan heeft zich al een aantal vragen gesteld, voordat hij besloot om die poging te wagen. Die vragen -en daarmee de stappen die hij doorloopt- zijn beter te introduceren aan de hand van het voorbeeld van een grotere softwareleverancier. Stel: Anne (43 jaar) werkt als product manager bij een commerciële softwareleverancier en heeft een aantal applicaties voor de gemeentelijke markt in haar portfolio. Ze ziet een API op een ontwikkelaarsportaal en beoordeelt aan de hand van de functionele specificaties of implementatie van de API meerwaarde biedt voor één van haar applicaties. Eén API trekt haar aandacht en Anne vraagt Steven (56 jaar, architect bij hetzelfde bedrijf) om te beoordelen of de API past binnen de software stack van het bedrijf. Steven ziet mogelijkheden en vervolgens krijgt Jeffrey (37 jaar, software engineer bij hetzelfde bedrijf) de opdracht om binnen een dag te beoordelen of hij de API succesvol kan integreren in de nieuwe versie van het product uit Anne’s portfolio. Na Jeffrey’s positieve oordeel besluit Gea, de manager, om tijd en geld vrij te maken voor implementatie. Zo komt de API uiteindelijk in de productieversie terecht.

Dit eindresultaat is bereikt, doordat in alle fases de ‘onboarding’ -het proces dat Anne, Steven en Jeffrey doorliepen toen zij voor de eerste keer gebruik maakten van een digitale service (het aanbieden van de API)- prettig verliep. Uit marketingonderzoeken blijkt een prettige eerste gebruikerservaring van een online platform (bijvoorbeeld het ontwikkelaarsportaal waarop Anne de API ontdekte en zij vervolgens samen met Steven en Jeffrey de API beoordeelde) veel invloed heeft op het verdere gebruik ervan. Oftewel: de kans is groot dat dit bedrijf vervolgens ook andere API’s op dit ontwikkelaarsportaal gaat gebruiken.

3.4 Specifieke aanbevelingen voor een goede DX

3.4.1 Aanbeveling 1: werk met (meerdere) persona’s

Een API ontwerp en bouw je niet voor een machine, maar voor een gebruiker: een mens! Om een goede DX te bieden, moet je dus eerst weten voor wie je ontwerpt en bouwt, voordat je dat goed kunt doen. Persona’s zijn dan belangrijk, er is niet maar één type developer! Redeneer van buiten naar binnen: wie zijn mijn gebruikers, wat willen zij kunnen doen en wat moet ik doen om dat zo goed mogelijk te faciliteren. Het typeren van gebruikers en analyseren welke behoeften zij hebben, doe je op basis van persona’s.

Belangrijk hierbij is om te onderkennen dat er verschillende niveaus of typen gebruik zijn. Onderscheid daarom -met de fases van ‘onboarding’ tot ‘in productie’ in het achterhoofd- minimaal de volgende persona’s:

  • een product manager / business developer: focus op het kunnen beoordelen van functionaliteit (“Is dit relevant voor mijn product / mijn doel?”)

  • een architect: focus op het beoordelen van het informatiemodel (“Hoe integreert dit met de rest van onze software?”)

  • een technische developer: focus op het daadwerkelijk kunnen gebruiken (“Hoe krijg ik dit werkend?”).

3.4.2 Aanbeveling 2: analyseer welke API’s je aan moet bieden: welke informatievragen wil je beantwoorden?

De ene API is de andere niet. In veel modellen worden API’s in drie categorieën onderverdeeld: de System API (die werkt op het niveau van de databron), de Process API (die doet aan orchestration door één of meerdere System API’s aan te roepen) en de Convenience of Experience API (die één specifieke gebruikersvraag beantwoord). Vraag je altijd af welke informatievragen de gebruiker heeft – in veel gevallen hangen deze vragen niet 1:1 samen met het datamodel.

Stel dat je de Basisregistratie Adressen en Gebouwen wil ontsluiten. De informatievraag “Geef me het volledige adres bij deze postcode” is alleen te beantwoorden door intern bij een Verblijfsobject de Openbare Ruimte naam, Nummeraanduiding en Woonplaats op te vragen en te combineren tot één adressering. Bij een System API moet je meerdere calls doen om dit adres op te bouwen, terwijl een Convenience API deze gangbare (maar complexe) vraag in één call kan beantwoorden. Het aanbieden van Convenience API’s naast System API’s is dus erg gebruiksvriendelijk: de 80% gebruikers die hiermee geholpen zijn, confronteer je met slechts 20% van de complexiteit. Vergelijk dit met de Toptaken-aanpak bij de websites van veel gemeenten: de meest aangevraagde producten (bijv. nieuw paspoort en rijbewijs) staan pontificaal op de homepage, terwijl de minder vaak gevraagde diensten op vervolgpagina’s staan. Zo reduceer je de complexiteit voor een zo groot mogelijk deel van je gebruikers.

3.4.3 Aanbeveling 3: documenteer gericht op de gebruiker, biedt snel inzicht en gebruik OAS 3

Elk type gebruiker dat in aanbeveling 1 wordt genoemd (business developer, architect, technische developer) verdient zijn eigen ‘Getting started’ documentatie, gericht op het snel kunnen beoordelen en/of toepassen. Documentatie is nooit een lijvig document (wanneer veel documentatie nodig lijkt, is de functionaliteit vermoedelijk te complex) én nooit een PDF: laat je gebruikers makkelijk klikken naar relevante onderdelen binnen én buiten de documentatie! Referentie-implementaties kunnen ook zinvol zijn om snel een indruk te bieden van functionaliteit. Voor de technische developer is de documentatie conform de Open API Specifiction 3.0 (OAS 3); deze staat in Nederland op de ‘Pas toe of leg uit-lijst’ van het Forum Standaardisatie.

3.4.4 Aanbeveling 4: minimaliseer Time to First Call met een goede Sandbox

Zorg dat een developer snel een werkend voorbeeld heeft. Dit vraagt om een goed gedocumenteerde, realistische Sandbox. Deze Sandbox dient alle aspecten van de API te ondersteunen en identiek gedrag aan de productieversie van de API te vertonen, bijvoorbeeld rond authenticatie. Daar waar mogelijk is het zeer wenselijk dat meerdere API’s dezelfde dataset bieden als Sandbox, zodat ook het samenspel tussen verschillende API’s getest kan worden.

3.4.5 Aanbeveling 5: borg ontwikkeling en beheer

Ook al is een API nog zo goed ontwikkeld, wanneer doorontwikkeling en beheer niet goed geregeld is, zal die API niet succesvol zijn. Essentieel hierin is dat je gebruikers duidelijkheid biedt:

3.4.5.1 Aanbeveling 5.1 Stel een SLA op

Maak duidelijk welke verwachtingen een gebruiker mag hebben qua uptime, service window, beprijzing etc.

3.4.5.2 Aanbeveling 5.2 Biedt een roadmap aan

Maak duidelijk of en zo ja, wanneer er eventuele wijzigingen te verwachten zijn en hoe lang de API minimaal beschikbaar blijft.

3.4.5.3 Aanbeveling 5.3 Doe aan versiebeheer

Borg dat de toepassing van de gebruiker blijft werken, door te zorgen voor backward compatability. Grotere updates kunnen als nieuwe versie worden uitgebracht, waarbij oudere versies nog een gegarandeerde periode beschikbaar blijven. Het versienummer kan in elke call staan, bijv. GET /api/v1.0/...

3.4.5.4 Aanbeveling 5.4 Sluit de feedback-loop: betrek de community

Om echt van buiten naar binnen te kunnen werken, is het betrekken van de community van gebruikers onmisbaar. De community kan vertellen hoe de developer experience tot nu toe is, welke verbeteringen wenselijk zijn, welke gebruikersvragen er sterk leven, maar nog onvoldoende ondersteund worden, etc., etc. Daarnaast wil je de community ook actief informeren over voorgenomen wijzigingen e.d. Het gebruik van API keys is een manier om je gebruikers te kennen.

3.4.6 Aanbeveling 6: maak duidelijk wat je data betekent

Wanneer je data openstelt voor derden, inclusief niet-specialisten, is het essentieel om eenduidig vast te leggen wat de data betekent, waarbij deze betekenis ook voor niet-specialisten begrijpelijk is. Het vastleggen van semantiek kan o.a. door definities en informatiemodellen goed te ontsluiten, maar ook door praktischere zaken als heldere naamgeving van variabelen etc.

3.4.7 Aanbeveling 7: wees vindbaar voor developers

Een goede, gebruiksgerichte API, die bovendien actief wordt beheerd en doorontwikkeld, kan nog steeds weinig gebruikt worden wanneer deze API niet goed vindbaar is. Zorg daarom dat je een goed developersportaal hebt, idealiter nationaal bij developer.overheid.nl. Presenteer breed toepasbare API’s en datasets daar prominenter dan specifiekere API’s en obscure datasets, wederom te vergelijken met de toptaken-aanpak bij gemeentelijke websites. Een goed developersportaal informeert niet alleen over beschikbare API’s, maar inspireert en verleidt zelfs developers om bepaalde API’s te gebruiken. Het vullen van het developersportaal mag daarom nooit sluitpost van een project zijn.

3.4.8 Aanbeveling 8: niet alles is een API!

Bedenkt altijd goed of een API de juiste oplossing is. In sommige gevallen is een bulk download nog steeds praktischer voor een gebruiker. Wanneer een API zinvol is? Hoe hoger de mutatiefrequentie van de data, hoe zinvoller een API wordt. En bij hoge mutatiefrequenties, is een API die was-wordt leveringen kan bieden zinvol.

4. API designrules (ontwerpregels)

Het doel van dit hoofdstuk is een set van regels te beschrijven op basis waarvan de hele overheid op eenduidige manier RESTful APIs (afgekort tot APIs) aan kan bieden. Hiermee wordt bereikt dat de overheid voorspelbaar is en ontwikkelaars makkelijk aan de slag kunnen en APIs kunnen consumeren en combineren. Vooralsnog is niet voorzien dat in dit hoofdstuk ook regels worden opgenomen voor ander type APIs zoals SOAP. In bijlage API-principes is de set van regels samengevat in een aantal principes die in de kern beschrijven waarmee rekening moet worden gehouden bij het ontwerpen en realiseren van API's

4.1 Inleiding

Binnen de overheid zijn meer en meer organisaties bezig met het implementeren en aanbieden van RESTful APIs, in veel gevallen worden deze APIs naast bestaande koppelvlakken zoals SOAP en WFS aangeboden om bestaande datasets te ontsluiten. Eén van de doelen die hiermee vaak nagestreefd wordt is het aanbieden van een API die developer friendly is (zie voor de uitleg hierover paragraaf 2.6 en hoofdstuk 3) en waarmee een developer snel aan de slag kan. Dit is uiteraard een mooi streven, maar het borgt nog niet dat een developer voor iedere nieuwe API niet alsnog een flinke leercurve heeft. Een developer moet uiteraard bij iedere nieuwe API wel begrijpen waarvoor de API ingezet kan worden, echter zou het niet nodig moeten zijn dat ook de technische werking tussen APIs sterk verschilt. Het Kennisplatform APIs heeft zich daarom als doel gesteld om te komen tot een set met designrules/ontwerpregels voor APIs waarmee APIs overheidsbreed technisch gezien vergelijkbaar werken en daarmee eenvoudiger worden om te implementeren. Dit hoofdstuk beschrijft de set met designrules die breed toepasbaar zijn. Vanuit het Kennisplatform APIs hopen we dat organisaties deze designrules gaan inzetten in hun eigen API strategie, dat eventuele uitzonderingen of aanvullingen terug gegeven worden aan het platform zodat de designrules verbeterd kunnen worden.

Belangrijk om in het achterhoofd te houden bij het realiseren van een API is dat de design rules die in dit hoofdstuk worden geschreven alleen toegepast dienen te worden als de beschreven functionaliteit gewenst is.

4.2 RESTful principes

Het belangrijkste principe van REST is het scheiden van de API in logische resources ("dingen"). De resources beschrijven de informatie van het "ding". Deze resources worden gemanipuleerd met behulp van HTTP-verzoeken en HTTP-operaties. Elke operatie (GET, POST, PUT, PATCH, DELETE) heeft een specifieke betekenis.

HTTP definieert ook operaties als HEAD, TRACE, OPTIONS en CONNECT. Deze worden echter in de context van REST vrijwel niet gebruikt en zijn daarom in de verdere uitwerking weggelaten.

Operatie CRUD Toelichting
POST Create Wordt gebruik als een "create" voor resources die collecties representeren (ofwel POST voegt een resource toe aan de collectie).
GET Read Wordt gebruikt om een resource op te vragen van de server. Data wordt alleen opgevraagd en niet gewijzigd.
PUT Update Wordt gebruikt om een specifieke resource te vervangen. Is óók een "create" wanneer de resource op aangegeven identifier/URI nog niet bestaat.
PATCH Update Wordt gebruikt om een bestaande resource gedeeltelijk bij te werken. Het verzoek bevat de gegevens die gewijzigd moeten worden en de operaties die de resource muteren in het daarvoor bedoelde JSON merge patch formaat (RFC 7386).
DELETE Delete Verwijdert een specifieke resource.

Per operatie is tevens bepaald of deze gegarandeerd "veilig" en/of "idempotent" moet zijn. Dit is van belang omdat afnemers en tussenliggende middleware hierop rekenen.

Veilig (alleen-lezen)

Veilig (alleen-lezen) betekent in dit geval dat de semantiek is gedefinieerd als alleen-lezen. Dit is van belang als afnemers en tussenliggende systemen gebruik willen maken van caching.

Idempotent

Onder idempotent wordt verstaan dat meerdere identieke verzoeken exact hetzelfde effect hebben als één verzoek.

Operatie Veilig Idempotent
POST Nee Nee
GET, OPTIONS, HEAD Ja Ja
PUT Nee Ja
PATCH Nee Optioneel
DELETE Nee Ja

API principe: API's garanderen dat operaties "Veilig" en/of "Idempotent" zijn

REST maakt gebruik van het client stateless server ontwerpprincipe dat is afgeleid van client server met als aanvullende beperking dat het niet toegestaan is om toestand (state) op de server bij te houden. Elk verzoek van de client naar de server moet alle informatie bevatten die nodig is om het verzoek te verwerken, zonder gebruik te hoeven maken van toestand-informatie op de server.

API principe: Toestandsinformatie wordt nooit op de server opgeslagen

4.2.1 Wat zijn resources?

Het fundamenteel concept in elke RESTful API is de resource. Een resource is een object met een type, bijbehorende data, relaties met andere resources en een aantal operaties om deze te bewerken. Resources worden aangeduid met zelfstandige naamwoorden (niet werkwoorden!) die relevant zijn vanuit het perspectief van de afnemer van de API. Dus resources zijn zelfstandige naamwoorden en operaties zijn werkwoorden. Operaties zijn acties die op resources worden uitgevoerd.

Het is mogelijk om interne datamodellen één-op-één toe te wijzen aan resources, maar dit hoeft niet per definitie zo te zijn. De crux is om alle niet relevante implementatiedetails te verbergen. Enkele voorbeelden van resources zijn: aanvraag, activiteit, pand, rijksmonument en vergunning.

Als de resources geïdentificeerd zijn, wordt bepaald welke operaties van toepassing zijn en hoe deze worden ondersteund door de API. RESTful API's realiseren CRUD (Create, Read, Update, Delete) operaties met behulp van HTTP-operaties:

Request Omschrijving
GET /aanvragen Haalt een lijst van aanvragen op
GET /aanvragen/12 Haalt een specifieke aanvraag op
POST /aanvragen Creëert een nieuwe aanvraag
PUT /aanvragen/12 Wijzigt aanvraag #12 als geheel
PATCH /aanvragen/12 Wijzigt een gedeelte van aanvraag #12
DELETE /aanvragen/12 Verwijdert aanvraag #12

Het mooie van REST is dat er gebruik wordt gemaakt van de bestaande HTTP operaties om de functionaliteit te implementeren met één enkel eindpunt. Hierdoor zijn er geen aanvullende naamgevingsconventies nodig in de URI en blijft de URIstructuur eenvoudig.

API principe: Alleen standaard HTTP-operaties worden toegepast

API principe: API-endpoints mogen géén trailing slashes bevatten

4.2.2 Welke taal?

Omdat de exacte betekenis van concepten en begrippen vaak in een vertaling verloren gaan, worden resources en de achterliggende entiteiten, velden, etc. in het Nederlands gedefinieerd.

API principe: Definitie van het koppelvlak is in het Nederlands tenzij er sprake is van een officieel Engelstalig begrippenkader

4.2.3 Naamgeving eindpunten in enkelvoud of meervoud?

De Keep It Simple Stupid (KISS) regel is hier van toepassing. Hoewel grammaticaal gezien het verkeerd aanvoelt om bij het opvragen van een enkele resource gebruik te maken van een resource naam in het meervoud, is het pragmatisch om te kiezen voor consistente eindpunten en altijd meervoud te gebruiken. Voor de afnemer is het gebruik veel eenvoudiger als er geen rekening gehouden hoeft te worden met enkel- en meervoud (aanvraag/aanvragen, regel/regels). Daarnaast is de implementatie eenvoudiger omdat de meeste ontwikkel frameworks het afhandelen van enkele resource (/aanvragen/12) en meervoudige resources (/aanvragen) met één controller kunnen oplossen.

API principe: Resource namen zijn zelfstandige naamwoorden in het meervoud

4.2.4 Hoe omgaan met relaties?

Als een relatie alleen kan bestaan binnen een andere resource (1-op-n relatie), dan kan de afhankelijke resource (kind) alleen via de ouder benaderd worden. Het volgende voorbeeld maakt dit duidelijk. Een status hoort bij één aanvraag. De statussen worden als volgt benaderd via het eindpunt /aanvragen:

Request Omschrijving
GET /aanvragen/12/statussen Haalt een lijst van statussen op van aanvraag #12
GET /aanvragen/12/statussen/5 Haalt een specifieke status (#5) van aanvraag #12 op
POST /aanvragen/12/statussen Creëert een nieuwe status voor aanvraag #12
PUT /aanvragen/12/statussen/5 Wijzigt status #5 van aanvraag #12
PATCH /aanvragen/12/statussen/5 Wijzigt een gedeelte van status #5 van aanvraag #12
DELETE /aanvragen/12/statussen/5 Verwijdert status #5 uit aanvraag #12

API principe: Relaties van geneste resources worden binnen het eindpunt gecreëerd

Indien er sprake is van een n-op-n relatie zijn er verschillende manieren om de resources te benaderen. De onderstaande verzoeken leveren hetzelfde resultaat op:

Request Omschrijving
GET /aanvragen/12/activiteiten Haalt een lijst van activiteiten op van aanvraag #12
GET /activiteiten?aanvraag=12 Haalt een lijst van activiteiten op, gefilterd op aanvraag #12

Bij een n-op-m relatie wordt het opvragen van de individuele resources sowieso ondersteund, waarbij minimaal de identificatie van gerelateerde resources (relatie) wordt teruggegeven. De afnemers moet zelf het eindpunt van de gerelativeerde resource (relatie) aanroepen om deze op te vragen. Dit wordt ook wel aangeduid als lazy loading. De afnemer bepaalt zelf of de relatie geladen wordt en op welk moment.

De resource dient naast "lazy loading" (de standaard) ook "eager loading" te ondersteunen, zodat de afnemer kan aangeven dat relaties direct meegeladen moeten worden. Dit wordt gerealiseerd middels de standaard query-parameter expand=true. Dit voorkomt dat er twee of meer aparte aanroepen nodig zijn. In beide gevallen is de afnemer in control.

API principe: Resources ondersteunen bij voorkeur "lazy" en "eager" laden van relaties

Issue 1

Lazy en eager loading worden in de volgende paragraaf nog een keer helemaal uitgelegd.

4.2.5 Automatische laden van gelinkte resources

Vaak wordt er vanuit één resource verwezen (gelinkt) naar andere (geneste) resources. De RESTful manier om dit op te lossen is de verwijzing naar andere resources als URI op te nemen in een resource. Op basis hiervan kan de afnemer, indien gewenst, de gelinkte resources zelf opvragen. Dit is vergelijkbaar met "lazy loading" in een Object Relational Mapping (ORM) oplossing: resources worden alleen opgehaald als ze nodig zijn. In sommige gevallen, als de afnemer alle resources nodig heeft, is het efficiënter als de geneste resources in één keer opgehaald worden. Dit is vergelijkbaar met "eager loading" patroon in een ORM-oplossing.

Omdat dit tegen de REST principes in gaat, moet het toepassen van dit mechanisme een expliciete keuze zijn. De keuze wordt bij de afnemers van de API belegd, zij weten immers of ze extra informatie nodig hebben en welke informatie precies. Dit mechanisme wordt mogelijk gemaakt met de expand query-parameter.

Als expand=true wordt meegegeven, dan worden alle geneste resources geladen en embedded in het resultaat teruggegeven. Om de hoeveelheid informatie die geretourneerd wordt te beperken, is verplicht om te specificeren welke resources en zelfs welke velden van een resource teruggeven moeten worden. Hiermee wordt voorkomen dat de hele database wordt leeg getrokken.

Dit wordt gedaan door de resources als een komma's gescheiden lijst te specificeren, bijvoorbeeld: expand=aanvrager,bevoegdGezag. De dot-notatie wordt gebruikt om specifieke velden van resources te selecteren. In het onderstaande voorbeeld wordt van de aanvrager alleen het veld "naam" teruggeven en van het bevoegd gezag de complete resource. Conform de [HAL]-standaard zijn de gelinkte resources embedded in de standaard representatie (zie ook aanpasbare representatie).

GET /aanvragen/12?expand=aanvrager.naam,bevoegdGezag

Dit levert het volgende resultaat op:

{
"id": "12",
"naam": "Mijn dakkapel",
"samenvatting": "Ik wil een dakkapel bouwen!",
"_embedded": {
  "aanvrager": {
    "naam": "Bob",
    "_links": {
      "self": {
        "href": "https: //.../api/register/v1/aanvragers/847",
        "title": "Bob"
      }
    }
  },
  "bevoegdGezag": {
    "id": "42",
    "soort": "Gemeente",
    "naam": "Rotterdam",
    "_links": {
      "self": {
        "href": "https: //.../api/register/v1/bevoegde-gezagen/42",
        "title": "Rotterdam"
      }
    }
  }
},
"_links": {
  "self": {
    "href": "https: //.../api/register/v1/aanvragen/12",
    "title": "Mijn dakkapel"
  }
}
}

Afhankelijk van de implementatie zal door het selectief kunnen laden van gelinkte resources in veel gevallen de overhead van database selecties, hoeveelheid serialisatie en hoeveelheid uitgewisselde data worden beperkt.

API principe: Gelinkte resources worden expliciet en selectief mee-geladen

4.2.6 Aanpasbare representatie

De gebruiker van een API heeft niet altijd de volledige representatie (lees: alle velden) van een resource nodig. De mogelijkheid bieden om de gewenste velden te selecteren helpt bij het beperken van het netwerkverkeer (relevant voor lichtgewicht toepassingen), vereenvoudigt het gebruik van de API en maakt deze aanpasbaar (op maat). Om dit mogelijk te maken wordt de query-parameter fields ondersteund. De query-parameter accepteert een door komma's gescheiden lijst met veldnamen. Het resultaat is een representatie op maat. Het volgende verzoek haalt bijvoorbeeld voldoende informatie op om een gesorteerde lijst van open aanvragen te tonen.

In het geval van HAL zijn de gelinkte resources embedded in de standaard representatie. Met de hier beschreven fields parameter ontstaat de mogelijkheid om de inhoud van de body naar behoefte aan te passen.

GET /aanvragen?fields=id,onderwerp,aanvrager,wijzigDatum&status=open&sorteer=wijzigDatum

API principe: Indien representatie op maat wordt ondersteund, dan conform dit principe

4.2.7 Hoe om te gaan met acties die niet passen in het CRUD model?

Er zijn ook resource-acties die niet data manipulatie (CRUD) gerelateerd zijn. Een voorbeeld van dit soort acties zijn: het wijzigen van de status (activeren en deactiveren) van een resource of het markeren (star) van een resource. Afhankelijk van het type actie zijn er drie manieren om dit aan te pakken:

  1. Herstructureer de actie zodat deze onderdeel wordt van een resource. Dit werkt als de actie geen parameters nodig heeft. Bijvoorbeeld een activeeractie kan worden toegewezen aan een booleaans veld geactiveerd dat bijgewerkt wordt via een PATCH op de resource.

  2. Behandel de actie als een sub-resource. Bijvoorbeeld, een aanvraag markeren met PUT /aanvragen/12/markeringen en verwijderen van de markering met DELETE /aanvragen/12/markeringen. Om de REST principes volledig te volgen moet ook de GET methode voor deze sub-resource beschikbaar zijn.

  3. Soms is er geen logische manier om een actie aan een bestaande resource te koppelen. Een voorbeeld hiervan is een zoekopdracht over meerdere resources heen. Deze actie kan niet worden toegekend aan een specifieke resource. In dit geval is de keuze voor een zelfstandig service-eindpunt /_zoek het meest logische. Gebruik werkwoorden in gebiedende wijs om het onderscheid t.o.v. "echte" resource endpoints zo duidelijk mogelijk te maken. Dit is vanuit het perspectief van de gebruiker het meest logisch ontwerp.

In de Nederlandse API-strategie wordt gekozen voor manier 2 en 3.

API principe: Acties die niet passen in het CRUD model worden een sub-resource

4.3 API Beveiliging

API's zijn vanaf elke locatie vanaf het internet te benaderen. Om uitgewisselde informatie af te schermen wordt altijd gebruik gemaakt van een versleutelde verbinding op basis van TLS. Geen uitzonderingen, dus overal en altijd.

Doordat de verbinding altijd is versleuteld is het authenticatiemechanisme eenvoudiger. Hierdoor wordt het mogelijk om eenvoudige toegangstokens te gebruiken in plaats van toegangstokens met encryptie.

API principe: De verbinding is ALTIJD versleuteld met minimaal TLS V1.2

API principe: API's zijn bij voorkeur alleen bruikbaar met behulp van een API-key

4.3.1 Authenticatie en autorisatie

Een REST API mag geen toestand (state) bijhouden. Dit betekent dat authenticatie en autorisatie van een verzoek niet mag afhangen van cookies of sessies. In plaats daarvan wordt elk verzoek voorzien van een token. Binnen het Kennisplatform APIs is gekozen voor OAuth 2.0 als de standaarden voor het autorisatiemechanisme waar dit nodig is. In hoofdstuk 5 is meer informatie te vinden over het gebruike van OAuth 2.0.

API principe: Tokens worden niet gebruikt in query parameters

Bij het gebruik van tokens wordt onderscheid gemaakt tussen geauthentiseerde en niet-geauthentiseerde services met de bijhorende headers:

Geauthentiseerd Authorization: Bearer <token>
Niet-geauthentiseerd X-Api-Key: <api-key>

Bij het ontbreken van de juiste headers zijn geen authenticatiedetails beschikbaar en dient de statuscode 403 Forbidden terug te worden gegeven.

API principe: Autorisatie is waar nodig gebaseerd op OAuth 2.0

Zie ook Het Nederlands profiel OAuth in het hoofdtuk beveiliging voor een nadere uitwerking van de toepassing van OAuth.

API principe: Authenticatie voor API's met toegangsbeperking of doelbinding is gebaseerd op PKIoverheid

4.3.1.1 Autorisatiefouten

In een productieomgeving is het wenselijk om voor het (kunnen) autoriseren zo min mogelijk informatie weg te geven. Met dit in het achterhoofd is het advies om voor statuscode 401 Unauthorized, 403 Forbidden en 404 Not Found, de volgende regels te hanteren:

Bestaat de resource? Kan de autorisatie worden bepaald? Geautoriseerd? HTTP statuscode
Ja Ja Ja 20x (200 OK)
Ja Ja Nee 401 Unauthorized
Ja Nee ? 403 Forbidden
Nee Ja Ja 404 Not Found
Nee Ja Nee 403 Forbidden
Nee Nee ? 403 Forbidden

Het idee van deze regels is dat eerst wordt bepaald of de aanroeper (principal) gerechtigd is voor een resource. Is het antwoord ‘nee' of kan dat niet worden bepaald, bijvoorbeeld omdat de resource nodig is om deze beslissing te kunnen nemen en de resource niet bestaat, dan wordt 403 Forbidden teruggegeven. Op deze manier wordt geen informatie teruggegeven over het al dan niet bestaan van een resource aan een niet-geautoriseerde principal.

Een bijkomend voordeel van de strategie om eerst te bepalen of er toegang is, meer ruimte biedt om de access control logica te scheiden van de business code.

4.3.1.2 Openbare identifiers

Openbaar zichtbare identifiers (ID's), zoals die veelal in URI's van RESTful API's voorkomen, zouden onderliggende mechanismen (zoals een nummergenerator) niet bloot moeten leggen en zeker geen zakelijke betekenis moeten hebben.

UUID

Het wordt aanbevolen om voor resources die een vertrouwelijk karakter hebben het concept van een UUID (Universally-Unique IDentifier) te gebruiken. Dit is een 16-bytes (128-bits) binaire representatie, weergegeven als een reeks van 32 hexadecimale cijfers, in vijf groepen gescheiden door koppeltekens en in totaal 36 tekens (32 alfanumerieke tekens plus vier afbreekstreepjes):

550e8400-e29b-41d4-a716-446655440000

Om te zorgen dat de UUID's korter en gegarandeerd "web-veilig" zijn, is het advies om alleen de base64-gecodeerde variant van 22 tekens te gebruiken. De bovenstaande UUID ziet er dan als volgt uit:

abcdEFh4520juieUKHWgJQ

4.3.1.3 Blootstellen API-key

De API-key's die standaard worden uitgegeven zijn "unrestricted". Dat wil zeggen dat er geen gebruiksbeperkingen op zitten en ze niet blootgesteld mogen worden via een webapplicatie. Door API-key's zonder gebruiksbeperkingen toe te passen in JavaScript, is er een reële kans op misbruik en quotum-diefstal. Om dit te voorkomen dienen in dit geval zogenaamde "restricted" API-key's te worden uitgegeven en gebruikt.

API principe: Gebruik "publieke" API-Key

4.3.1.4 CORS-policy

Webbrowsers implementeren een zogenaamde "same origin policy", een belangrijk beveiligingsconcept om te voorkomen dat verzoeken naar een ander domein gaan dan waarop het is aangeboden. Hoewel dit beleid effectief is in het voorkomen van aanroepen in verschillende domeinen, voorkomt het ook legitieme interactie tussen een API's en clients van een bekende en vertrouwde oorsprong.

API principe: Controleer toegang en gebruik CORS-header

4.4 Documentatie

Een API is zo goed als de bijbehorende documentatie. De documentatie moet gemakkelijk te vinden, te doorzoeken en publiekelijk toegankelijk zijn. De meeste ontwikkelaars zullen eerst de documenten doornemen voordat ze starten met de implementatie. Wanneer de documentatie is weggestopt in pdf-bestanden en achter een inlog, dan vormt dit een drempel voor ontwikkelaars om aan de gang te gaan en de documentatie is niet vindbaar met zoekmachines. Specificaties (documentatie) zijn beschikbaar als Open API Specification (OAS)9 V3.0 of hoger.

API principe: Documentatie is gebaseerd op OAS 3.0 of hoger

API principe: Documentatie is in het Nederlands tenzij er sprake is van bestaande documentatie in het Engels of er sprake is van een officieel Engelstalig begrippenkader

De documentatie dient voorzien te zijn van voorbeelden inclusief complete request en response cycli. Het moet mogelijk zijn om direct vanuit de documentatie verzoeken te testen (uit te voeren). Daarnaast is elke fout beschreven en voorzien van een unieke foutcode die gebruikt kan worden om de fout op te zoeken.

Als een API in productie is mag het "contract" (koppelvlak) niet zonder voorafgaande kennisgeving worden gewijzigd. De documentatie moet voorzien zijn van een uitfaseringsplanning (deprecation schedule) en alle details van de wijziging bevatten. Wijzigingen worden via een publiek toegankelijke blog als changelog bekendgemaakt en via een mailinglijst. Hierbij wordt primair gebruik gemaakt van de emailadressen die zijn gekoppeld aan de uitgifte van API-keys.

API principe: Wijzigingen worden gepubliceerd met een uitfaseringschema

4.4.1 Best practice(s)

API principe: OAS via basis-URI beschikbaar in JSON-formaat

4.5 Versionering

API's zijn altijd geversioneerd. Versioneren zorgt voor een soepele overgang bij wijzigingen. De oude en nieuwe versies worden voor een beperkte overgangsperiode (één jaar) aangeboden. Er worden bovendien maximaal 3 versies van een API ondersteund. Afnemers kiezen zelf het moment dat ze overschakelen van de oude naar de nieuwe versie van een API, als ze het maar voor het einde van de overgangsperiode is.

API principe: De overgangsperiode bij een nieuwe API versie is maximaal 1 jaar

Oude en nieuwe versies (max. 3) van een API worden voor een beperkte overgangsperiode (1 jaar) naast elkaar aangeboden.

Er zijn verschillende meningen over de vraag of de versie in de URI of in de header hoort. Het Kennisplatform APIs heeft hier een keuze in gemaakt: alleen het major versienummer wordt in de URI opgenomen. Hierdoor is het mogelijk om verschillende versies van een API via de browser te verkennen.

Het versienummer begint bij 1 en wordt met 1 opgehoogd voor elke major release waarbij het koppelvlak niet backward compatible wijzigt. De minor en patch versienummers staan altijd in de response-header van het bericht zelf in het formaat major.minor.patch.

De header (zowel request als response) is als volgt gedefinieerd:

HTTP header Toelichting
API-Version Geeft een specifieke API-versie aan in de context van een specifieke aanroep. Bijvoorbeeld: API-version: 1.2.56

Via de optionele request-header kan één minor/patch-versie worden aangewezen. Hiermee wordt bedoeld dat in (pre)productie- of aansluitomgeving naast bijvoorbeeld v1 en v2 (de aangewezen versies die alleen bereikbaar zijn via de URI's) ook nog de mogelijkheid bestaat om één "oudere" of "nieuwere" versie van deze API's aan te wijzen en via de request-header te benaderen. De onderstaande URI's wijzen bijvoorbeeld naar de aangewezen productie-release van de API die alleen bereikbaar zijn via de URI:

https://service.omgevingswet.overheid.nl/publiek/catalogus/api/raadplegen/v1

API-version: 1.0.2 (response header)

https://service.omgevingswet.overheid.nl/publiek/catalogus/api/raadplegen/v2

API-version: 2.1.0 (response header)

Het weglaten van de request-header (API-version: x.y.z) selecteert altijd de "aangewezen" productieversie. Indien er voor V2 ook één andere aangewezen versie beschikbaar is, met bijvoorbeeld versienummer V2.1.1, dan kan deze via hetzelfde basis endpoint worden aangeboden en geselecteerd door het meegeven van de juiste request-parameter:

API-version: 2.1.1 (request header)

https://service.omgevingswet.overheid.nl/publiek/catalogus/api/raadplegen/v2

API-version: 2.1.1 (response header)

Het toevoegen van een endpoint of een niet verplichte attribuut aan de payload zijn voorbeelden van wijzigingen die backward compatible zijn.

API principe: Alleen het major versienummer is onderdeel van de URI

In de URI wordt alleen het major versienummer opgenomen. Minor versienummer en patch versienummer worden in de header van het bericht zelf opgenomen. Het uitgangspunt dat hierbij wordt gehanteerd is dat minor versies en patches geen impact hebben op bestaande code, maar major versies wel.

Een API zal nooit helemaal stabiel zijn. Verandering is onvermijdelijk. Het is belangrijk hoe met deze verandering wordt omgegaan. Goed gedocumenteerde en tijdig gecommuniceerde uitfaseringsplanningen zijn in het algemeen voor veel APIgebruikers werkbaar.

4.5.1 Uitfaseren van een major API versie

Major releases van API's zijn altijd backward incompatible. Immers, als een nieuwe release van de API niet tot backward incompatibiliteit leidt, is er geen reden om een hele versie omhoog te gaan en spreken we van een minor release. Op het moment dat er een major release plaatsvindt, is het de bedoeling dat alle (potentiële) clients deze nieuwe versie implementeren.

Omdat we geen clients willen breken kunnen we niet van de een op de andere dag overschakelen van de oude naar de nieuwe versie, zoals dat bijvoorbeeld bij een update van een website wel vaak gebeurt. Daarom is het noodzakelijk om na de livegang van de nieuwe versie óók de oude versie in de lucht te houden. Omdat we de oude versie niet tot in de eeuwigheid willen blijven onderhouden en juist iedereen willen stimuleren om de nieuwe versie te gaan gebruiken, communiceren we een periode waarin clients de gelegenheid krijgen om hun code aan te passen aan de nieuwe versie. Deze periode noemen we de deprecation periode. De lengte van deze periode kan verschillen per API, vaak is dit zes maanden, maar niet meer dan één jaar. Met het oog op beheersbaarheid is het ten zeerste aan te bevelen om maximaal twee major versies (waarvan één de deprecated variant) naast elkaar te draaien. In deze fase is communicatie met clients van de oude versie cruciaal. De volgende zaken moeten gecommuniceerd worden:

  • Een link naar de (documentatie van de) nieuwe versie van de API;
  • Deprecation periode met exacte datum waarop de deprecated versie offline wordt gehaald;
  • Migratieplan om eenvoudig over te stappen naar de nieuwe versie;
  • Welke features er toegevoegd, gewijzigd of verwijderd worden;
  • Welke wijzigingen de huidige implementaties kunnen breken;
  • Contactmogelijkheid om een verlenging van de deprecation periode aan te vragen.

Deze zaken dienen gecommuniceerd te worden via de volgende kanalen:

  • Per e-mail van de clients (indien bekend);
  • Duidelijk leesbaar in de API documentatie van de oude versie;
  • Met een Warning response header in alle responses van de oude API.

Stap voor stap betekent dit het volgende:

  1. Lanceren nieuwe versie;
  2. Bepalen deprecation periode;
  3. Schrijven migratieplan;
  4. Communiceren in de API-documentatie van de oude versie;
  5. Deprecation periode communiceren per e-mail, forum en eventuele andere kanalen;
  6. Warning header toevoegen aan responses van de oude versie;
  7. Logs checken om gebruik van de oude versie te monitoren gedurende deprecation periode;
  8. End-point oude versie dichtzetten op geplande datum en feedback monitoren;
  9. Indien er binnen twee weken geen feedback op de oude versie komt kan de oude versie (inclusief docs) verwijderd worden;

4.5.2 De Warning response header

De Warning header (zie: RFC 7234) die we hier gebruiken heeft warn-code 299 ("Miscellaneous Persistent Warning") en het API endpoint (inclusief versienummer) als de warn-agent van de warning, gevolgd door de warn-text met de human-readable waarschuwing. Voorbeeld:

Waarschuwing: 299 https://service.../api/.../v1 "Deze versie van de API is verouderd en zal uit dienst worden genomen op 2018-02-01. Raadpleeg voor meer informatie hier de documentatie: https://omgevingswet.../api/.../v1".

Gebruikers moeten voldoende tijd hebben om de oude API uit te faseren. Een periode van 6 tot 12 maanden wordt aanbevolen.

API principe: Gebruikers van een 'deprecated' API worden actief gewaarschuwd

4.6 JSON

JavaScript Object Notation (JSON) is een formaat, net zoals XML, om gegevens te serialiseren, op te slaan en te versturen. JSON is het primaire representatieformaat voor API's. In tegenstelling tot XML kent JSON een compacte notatie, bijvoorbeeld:

{
"persoon": {
  "naam": "Jan",
  "geboortejaar": 1983
}
}

API principe: JSON first - API's ontvangen en versturen JSON

API principe: API's zijn optioneel voorzien van een JSON Schema

API principe: Content negotiation wordt volledig ondersteund

API principe: API's controleren dat de Content-Type header is ingesteld

4.6.1 Veldnamen in snake_case, camelCase, UpperCamelCase of kebab-case?

Bij veldnamen wordt gebruik gemaakt van camelCase.

API principe: Woorden in veldnamen zijn gedefinieerd in camelCase

4.6.2 Pretty print

De meeste REST clients en browsers (al dan niet met extensies) kunnen JSON netjes geformatteerd weergeven, ook als de response geen white-space bevat.

API principe: Pretty print is standaard uitgeschakeld

4.6.3 Gebruik geen envelop

Veel API's wikkelen antwoorden in enveloppen zoals hieronder is weergegeven:

{
"persoon": {
  "naam": "Jan",
  "geboortejaar": 1983
}
}

Een toekomstbestendig API is vrij van enveloppen.

API principe: Een JSON-response heeft geen omhullende envelop

4.6.4 JSON gecodeerde POST, PUT en PATCH payloads

API's ondersteunen minimaal JSON gecodeerde POST, PUT en PATCH payloads. Encoded form data (application/x-www-form-urlencoded) payloads worden niet ondersteund. Wat is het verschil?

Content-Type: application/json resulteert in:

{
"Name": "John Smith",
"Age": 23
}

en Content-Type: application/x-www-form-urlencoded resulteert in: Name=John+Smith&Age=23

API principe: API's ondersteunen JSON gecodeerde POST, PUT en PATCH payloads

4.7 Filteren, sorteren en zoeken

Er wordt gekozen om de basis URL's van resources zo eenvoudig mogelijk te houden. Complexe resultaatfilters, sorteren en geavanceerd zoeken (wanneer dit beperkt blijft tot een enkele resource) worden geïmplementeerd als query-parameters bovenop de basis URL.

4.7.1 Filteren

Om te filteren wordt gebruik gemaakt van unieke query-parameters die gelijk zijn aan de velden waarop gefilterd kan worden. Als je bijvoorbeeld een lijst met aanvragen wilt opvragen van het eindpunt /aanvragen en deze wilt beperken tot open aanvragen, dan wordt het verzoek GET /aanvragen?status=open gebruikt. Hier is status een veld waarop gefilterd kan worden.

API principe: Filter query-parameters zijn gelijk aan de velden waarop gefilterd kan worden

Dezelfde systematiek kan worden gehanteerd voor geneste properties. Zoals uitgewerkt met een voorbeeld op basis van de volgende collectie:

[{
"id": 1,
"status": "actief",
"overheid": {
  "code": "0000",
  "naam": "Ministerie van BZK"
}
}, {
"id": 2,
"status": "inactief",
"overheid": {
  "code": "9901",
  "naam": "Provincie Gelderland"
}
}]

Alle objecten met de status "actief" kunnen worden gefilterd met /?status=actief. Maar als daarnaast ook op objecten met code "0000" van de overheid gefilterd moeten worden, heeft dit betrekking op een geneste property. Hier kan dan de puntnotatie (zoals bij Javascript) voor worden gebruikt: /?status=actief&overheid.code=0000.

4.7.2 Sorteren

Voor sorteren wordt de query-parameter sorteer gebruikt. Deze query-parameter accepteert een lijst van velden waarop gesorteerd moet worden gescheiden door een komma. Door een minteken ("-") voor de veldnaam te zetten wordt het veld in aflopende sorteervolgorde gesorteerd. Een aantal voorbeelden:

Request Toelichting
GET /aanvragen?sorteer=-prio Haalt een lijst van aanvragen op gesorteerd in aflopende volgorde van prioriteit.
GET /aanvragen?sorteer=-prio,aanvraagDatum Haalt een lijst van aanvragen in aflopende volgorde van prioriteit op. Binnen een specifieke prioriteit, komen oudere aanvragen eerst.

API principe: Voor sorteren wordt de query-parameter sorteer gebruikt

4.7.3 Zoeken

Soms zijn eenvoudige filters onvoldoende en is de kracht van vrije-tekst zoekmachines nodig. API's ondersteunen dit middels de query-parameter zoek. Het resultaat wordt in dezelfde representatie teruggegeven.

API principe: Voor vrije-tekst zoeken wordt een query-parameter zoek gebruikt

Voorbeelden van de combinatie filteren, sorteren en zoeken:

Request Toelichting
GET /aanvragen?sorteer=-wijzigingDatum Haalt een lijst van recente aanvragen op
GET /aanvragen?status=gesloten&sorteer=-wijzigingDatum Haalt een lijst van recent gesloten aanvragen op
GET /aanvragen?zoek=urgent&status=open&sorteer=-prio,aanvraagDatum Haalt een lijst van aanvragen op met de status 'open' en waarin het woord 'urgent' voorkomt, gesorteerd van hoogste naar laagste prioriteit, en daarbinnen op aanvraagdatum van oud naar nieuw

4.7.4 Wildcards

API's die vrije-tekst zoeken ondersteunen kunnen overweg met twee soorten wildcard karakters:

  • * Komt overeen met nul of meer (niet-spatie) karakters
  • ? Komt precies overeen met één (niet-spatie) karakter

Bijvoorbeeld, he* zal overeenkomen met elk woord dat begint met he, zoals hek, hemelwaterafvoer, enzovoort. In het geval van he? komt dit alleen overeen met drie letterwoorden die beginnen met he, zoals hek, heg, enzovoort.

API principe: API's die vrije-tekst zoeken ondersteunen kunnen overweg met twee soorten wildcard karakters: * en ?

Hieronder volgen nog een aantal basisregels voor wildcards in zoekopdrachten:

  • Er kan meer dan één wildcard in één zoekterm of zin voorkomen.
  • De twee wildcard karakters kunnen in combinatie worden gebruikt. Bijvoorbeeld m*?? komt overeen met woorden die beginnen met m en drie of meer tekens hebben.
  • Spaties (URL-encoded als %20) worden gebruikt als woordscheiding en wildcardmatching werkt alleen binnen een enkel woord. Bijvoorbeeld, r*te* komt overeen met de ruimtelijk, maar niet met ruimte tekort.
  • Wildcards werken alleen op JSON-velden met tekst (string) waarden.

4.7.5 Aliassen voor terugkerende queries

Om de API ervaring verder te verbeteren is het mogelijk om terugkerende queries als endpoints aan te bieden. Zo kunnen onlangs gesloten aanvragen als volgt worden benaderd:

GET /aanvragen/recent-gesloten

4.8 Tijdreizen

Informatie over een resource is onderhevig aan verandering. Tijdreizen is een mechanisme waarmee het mogelijk is om op standaard manier informatie op te vragen over een bepaald moment in de tijd. De drie belangrijkste tijdsmomenten vanuit het perspectief van tijdreizen via een API zijn:

Tijdsmoment Omschrijving
Geldig Dit is een tijdstip waarop de teruggegeven gegevens in de werkelijkheid geldig zijn.
Beschikbaar Dit is een tijdstip waarop geldt dat de teruggegeven gegevens beschikbaar waren via dezelfde API.
In werking (getreden op) Dit is een tijdstip waarop een besluit (of delen daarvan), dan wel de daarvan afgeleide gegevens (zoals de definitie van een begrip) juridische werking krijgt.

Het basisprincipe voor het tijdreizen is daarbij als volgt:

De waarden van de drie query-parameters in de URI zijn als volgt opgebouwd (gebaseerd op RFC3339 / ISO 8601):

Parameter Waarde
geldigOp YYYY-MM-DD
beschikbaarOp YYYY-MM-DDThh:mm:ss.s
inWerkingOp YYYY-MM-DD
Waarde Betekenis
YYYY Viercijferig jaar
MM Tweecijferige maand (01 = januari, enz.)
DD Tweecijferige dag van de maand (01 tot en met 31)
hh Twee cijfers van het uur (00 tot 23) (am / pm niet toegestaan)
mm Twee cijfers van de minuut (00 tot en met 59)
ss twee cijfers van de seconden (00 tot en met 59)
s Eén of meer cijfers die een decimale fractie van een seconde vertegenwoordigen

4.8.1 Mate van ondersteuning

Tijdreizen is een optioneel mechanisme met optionele features. Het kan dus voorkomen dat:

  • tijdreizen in het geheel niet wordt ondersteund;
  • het begrip inwerkingtreding niet wordt ondersteund;
  • tijdreizen naar de toekomst niet wordt ondersteund.

Bij de verwerking van tijdreisvragen dient de afnemer geïnformeerd te worden over ongeldige/niet ondersteunde verzoeken. In de volgende specifieke gevallen wordt de bijbehorende statuscode en toelichting teruggegeven:

Wat wordt niet ondersteund? HTTP statuscode en toelichting
Tijdreizen HTTP/1.1 403 Content-Type: application/problem+json Content-Language: nl { "type": ".../id/<c>/parameter/TijdreizenNietOndersteund", "title": "{Het verzoek is begrepen, maar de tijdreisparameters worden niet ondersteund}", "status": 403, "detail": "{Tijdreizen wordt niet ondersteund, verwijder alle tijdreisparameters}", "instance": "/resource/#id"}
Inwerkingtreding HTTP/1.1 403 Content-Type: application/problem+json Content-Language: nl { "type":".../id/<c>/parameter/InWerkingTredingNietOndersteund’", "title": "{Het verzoek is begrepen, maar de tijdreisparameter ‘inWerkingOp’ wordt niet ondersteund}", "status": 403, "detail": "{Tijdreizen met een inwerkingstredingsmoment wordt niet ondersteund, verwijder de parameter ‘inWerkingOp’}", "instance": "/resource/#id"}
Toekomst HTTP/1.1 403 Content-Type: application/problem+json Content-Language: nl { "type": ".../id/<c>/parameter/ToekomstNietOndersteund", "title": "{Het verzoek is begrepen, maar tijdreisparameters mogen geen tijdstip in de toekomst bevatten” }", "status": 403, "detail": "{Tijdreizen naar de toekomst wordt niet ondersteund, verwijder de tijdreisparameters of gebruik een tijdstip in het verleden}", "instance": "/resource/#id"}

4.8.2 Robuustheid

Bij de verwerking van tijdreisvragen dient ook rekening te worden gehouden met het ontbreken van historie en globale vragen in een resource-collectie. In volgende specifieke gevallen wordt de bijbehorende statuscode en toelichting teruggegeven:

Soort verzoek HTTP statuscode en toelichting
Specifieke resource HTTP/1.1 404 Content-Type: application/problem+json Content-Language: nl {"type": ".../id/<c>/BestaatNiet", "title": "De gevraagde versie bestaat niet.", "status": 404, "detail": "Versie 2017-01-01 van regeling 123 bestaat niet.", "instance": "/regelingen/v1/123?geldigOp=2017-01-01"}
Resource-collectie GET .../regelingen/v1?beschikbaarOp=2017-01-01T00:00:00 HTTP/1.1 200 Content-Type: application/json+hal {"_links": {"self": {"href": "/r-n/v1/123?beschikbaarOp=2017-01-01T00:00:00" }, "items": [ { "href": "/r-n/v1/123?beschikbaarOp=2017-01-01T00:00:00" }, { "href": "/r-n/v1/456?beschikbaarOp=2017-01-01T00:00:00" }, { "href": "/r-n/v1/789?beschikbaarOp=2017-01-01T00:00:00" }] } }

4.9 GEO-ondersteuning

REST API's voor het werken met geometrieën kunnen een filter aanbieden op basis van geografische gegevens. Het is hierbij belangrijk om een onderscheid te maken tussen een geometrie in het resultaat (response) en een geografische filter in de aanroep (request). Het is immers niet vanzelfsprekend dat als iemand wil weten in welk perceel ik hij/zij zich momenteel bevindt, dat ook de geometrie in de response wordt teruggegeven; een naam of nummer kan dan al voldoende zijn.

API principe: GEO API's ontvangen en versturen bij voorkeur GeoJSON

Voor GEO API's wordt bij voorkeur de standaard GeoJSON [rfc8142] gebruikt.

4.9.1 Resultaat (response)

In een JSON API wordt een geometrie teruggegeven als GeoJSON. We kiezen er voor om dit binnen de application/json te ‘wrappen' in een apart GeoJSON object.

API principe: GeoJSON is onderdeel van de embedded resource in de JSON response

4.9.2 Aanroep (requests)

Een geografisch filter kan erg complex en groot zijn. Het is daarom een best practice om dergelijke complexe vragen niet in de request URI, maar in de body mee te sturen. Omdat GET geen payload mag hebben (hoewel sommige clients dit wel ondersteunen) moet hier dus een andere methode voor gebruikt worden.

In analogie met API's zoals die van Elasticsearch, is een POST naar een apart endpoint de juiste weg om te bewandelen. Het onderstaande voorbeeld doet een zogenaamde GEO-query naar alle panden waarin het veld _geo (er kunnen ook andere velden zijn, zoals hoofdgeometrie, binnenOmtrek, buitenOmtrek, etc.) het GeoJSON object (in dit geval een Point, dus één coördinaat) bevat:

// POST /api/v1/panden/_zoek met request body:
{
"_geo": {
  "contains": {
    "type": "Point",
    "coordinates": [5.9623762, 52.2118093]
  }
}
}

API principe: Voor GEO queries is een POST endpoint beschikbaar

Omdat we ons met het geo endpoint beperken tot een GEO-query en we wellicht ook gecombineerde queries willen doen is het sterk aan te bevelen om een generiek query endpoint in te richten:

// POST /api/v1/panden/_zoek met request body:
{
"_geo": {
  "contains": {
    "type": "Point",
    "coordinates": [5.9623762, 52.2118093]
  }
},
"status": "Actief"
}

API principe: POST endpoints zijn uitbreidbaar voor gecombineerde vragen

Naast contains kan er ook intersects (snijdt) of within (valt binnen) als operators gebruikt worden. De benamingen van deze operators komen uit de GEO-wereld en die willen we niet opnieuw uitvinden. Zie voor meer details: https://www.w3.org/TR/sdw-bp/#entity-level-links

Omdat we voor de geometrie een GeoJSON object gebruiken hoeven we hier geen syntax meer voor te verzinnen.

API principe: Resultaten van een globale zoekvraag worden in de relevante context geplaatst

In het volgende voorbeeld wordt aangegeven hoe dit kan worden gerealiseerd:

// POST /api/v1/_zoek:
{
"_embedded": {
  "results": [{
    "type": "enkelbestemming",
    "_links": {
      "self": {
        "title": "Enkelbestemming 1234",
        "href": "/enkelbestemmingen/1234"
      }
    }
  }, {
    "type": "dubbelbestemming",
    "_links": {
      "self": {
        "title": "Dubbelbestemming 8765",
        "href": "/dubbelbestemmingen/8765"
      }
    }
  }]
}
}

4.9.3 CRS-negotiation

Het default CRS (Coordinate Reference System) van GeoJSON is WGS84. Dit is het globale coördinatenstelsel dat overal ter wereld redelijk goed bruikbaar is, maar vanwege het gebruikte model van de aarde en de verschuiving van de tektonische platen minder nauwkeurig is dan lokale coördinatenstelsels zoals ETRS89 (EPSG:4258, Europees) of RD (EPSG:28992, Nederlands).

Omdat de meeste client-bibliotheken met WGS84 werken, schrijft de W3C/OGC werkgroep "Spatial Data on the Web" voor om dit standaard te ontsluiten. Dit kan direct op een kaart geplot worden zonder moeilijke transformaties. De API-strategie voorziet hierin door naast ETRS89 en RD ook WGS84 of Web Mercator (EPSG:3857, voor rasterdata) te ondersteunen.

API principe: Het voorkeur-coördinatenstelsels (CRS) is ETRS89, maar het CRS wordt niet impliciet geselecteerd

Het is mogelijk om het CRS voor vraag en antwoord via headers afzonderlijk te specificeren. Hierin zijn vervolgens drie opties (met voorgeschreven projecties) voorhanden: RD, ETRS89 en WGS84.

Een nadere opsomming van de uitgangspunten voor het CRS:

  • Leg als bronsysteem binnenkomende formaat vast (juridische context);
  • Coördinatenstelsels API-strategie: vraag/antwoord in RD; ETRS89; WGS84;
  • Overweeg no-regret: vastleggen in ETRS89 én RD i.p.v. realtime bepalen;
  • Hanteer RDNAPTRANS™ 2018 bij transformatie RD versus ETRS89 (correctiegrid);
  • Presentatie afhankelijk van context (o.a. gebruikerswensen);
  • Uitwisselingsformaat (notatie) ETRS89 en WGS84 X Y in decimale graden: DD.ddddddddd (voorbeeld: 52.255023450)
  • Uitwisselingsformaat (notatie) RD X Y in meters (niet afgerond): 195427.5200 311611.8400

API principe: Het coördinatenstelsel (CRS) van de vraag en het antwoord wordt in de header meegestuurd

De hier genoemde headers zijn puur bedoeld voor de onderhandeling tussen de client en de server. Afhankelijk van de toepassing zal naast de geometrieën ook specifieke metadata onderdeel vormen van het antwoord, bijvoorbeeld de oorspronkelijke realisatie inclusief een inwindatum.

Vraag en antwoord kunnen op een ander coördinatensysteem zijn gebaseerd. Hiervoor wordt het HTTP-mechanisme voor content negotiation gebruikt. Het CRS van de geometrie in de vraag (request body) wordt aangeduid met de header Content-Crs.

HTTP header Waarde Toelichting
Content-Crs EPSG:3856 WGS84, Wereld (Web-Mercator-projectie)
Content-Crs EPSG:4258 ETRS89, Europees
Content-Crs EPSG:28992 RD, Nederlands

Het gewenste CRS voor de geometrie in het antwoord (response body) wordt aangeduid met de header Accept-Crs.

HTTP header Waarde Toelichting
Accept-Crs EPSG:3856 WGS84, Wereld (Web-Mercator-projectie)
Accept-Crs EPSG:4258 ETRS89, Europees
Accept-Crs EPSG:28992 RD, Nederlands

4.9.4 CRS-transformatie

Voor het transformeren tussen coördinaatreferentiesystemen is binnen de Rijksoverheid software met een keurmerk beschikbaar.

API principe: Het gewenste coördinatenstelsel wordt op basis van content negotiation overeengekomen

4.10 Paginering

Voor paginering wordt voor het media type 'application/hal+json' aangesloten op Hypertext Application Language (HAL). Aan geretourneerde objecten worden twee gereserveerde velden _links (verplicht) en _embedded (optioneel) toegevoegd. Deze velden vertegenwoordigen respectievelijk hyperlinks en embedded resources.

Hier is een voorbeeld van een JSON+HAL representatie:

{
"_links": {
  "self": {
    "href": "https://.../api/registratie/v1/aanvragen?pagina=3"
  },
  "first": {
    "href": "https://.../api/registratie/v1/aanvragen"
  },
  "prev": {
    "href": "https://.../api/registratie/v1/aanvragen?pagina=2"
  },
  "next": {
    "href": "https://.../api/registratie/v1/aanvragen?pagina=4"
  },
  "last": {
    "href": "https://.../api/registratie/v1/aanvragen?pagina=5"
  }
},
"id": "https://.../api/registratie/v1/aanvragen/12",
"naam": "Mijn dakkapel",
"samenvatting": "Ik wil een dakkapel bouwen!",
"_embedded": {
  "aanvrager": {
    "naam": "Bob"
  }
}
}

Indien het "plain" JSON, GeoJSON of iets anders dan HAL betreft zijn er geen _links. Deze kunnen dan opgenomen worden in de link response headers. Naast de representatie wordt de volgende metadata teruggegeven als HTTP headers.

HTTP header Toelichting
X-Total-Count (optioneel) Totaal aantal resultaten
X-Pagination-Count (optioneel) Totaal aantal pagina's
X-Pagination-Page (optioneel) Huidige pagina
X-Pagination-Limit (optioneel) Aantal resultaten per pagina

Bij grote datasets kunnen de berekeningen voor X-Total-Count en X-Pagination-Count behoorlijke impact hebben op de performance, voornamelijk als er niet of nauwelijks gefilterd wordt.

API principe: Paginering wordt gerealiseerd op basis van JSON+HAL bij media type: application/hal+json

Alle links in HAL zijn absoluut. Dit in verband met mogelijke externe links (naar andere endpoints, linked-data resources, etc.) en eenvoudigere navigatie door clients ie dan niet zelf de URL hoeven op te bouwen.

4.11 Caching

Voor sommige resources kan het nuttig zijn om caching toe te passen. HTTP biedt voor caching standaard mechanismes. Door deze mechanismes te gebruiken wordt gebruik gemaakt van standaard caching oplossingen van de client en in de infrastructuur.

Het enige wat nodig is om hiervan gebruik te maken is:

Er zijn 2 manieren om caching te realiseren: ETag en Last-Modified.

4.11.1 ETag

Een ETag (Entity Tag) is een hashcode of checksum van een resource. Als de resource wijzigt ontstaat een andere ETag. Een ETag is dus uniek voor een bepaalde versie van een resource. De ETag wordt als de HTTP header ETag teruggegeven met de resource. De afnemer cached de resource en de ETag. Als de afnemer dezelfde resource opvraagt dan stuurt deze de ETag mee in de HTTP header If-None-Match. De server controleert of de ETag in de HTTP header If-None-Match gelijk is aan de eigen ETag. Indien dit het geval geeft de server een HTTP statuscode 304 Not Modified terug. De afnemer laadt dan de resource uit de eigen cache. Dit gaat alleen op over clientside caching, dus is alleen van toepassing als de client ook daadwerkelijk de request headers meestuurt, anders altijd een 200 OK.

4.11.2 Last-Modified

Dit werkt in principe net als ETag, behalve dat het gebruik maakt van tijdstempels. De HTTP header Last-Modified bevat een tijdstempel in het RFC 1123 formaat die wordt gevalideerd tegen de HTTP header If-Modified-Since. De server controleert of de resource gewijzigd is sinds het aangegeven tijdstip. Indien dit niet het geval is dan geeft de server een HTTP statuscode 304 Not Modified terug. De afnemer laadt dan de resource uit de eigen cache. Dit gaat alleen op over client-side caching, dus is alleen van toepassing als de client ook daadwerkelijk de request headers meestuurt, anders altijd een 200 OK.

API principe: Waar relevant wordt caching toegepast

4.12 Begrenzingen

API's beperken het aantal verzoeken dat per tijdsperiode gedaan kan worden, om te voorkomen dat de servers overbelast worden om een hoog serviceniveau te garanderen. API's kunnen een bevragingslimiet (quota) per maand bijhouden en die wordt afgedwongen per tijdsperiode van 60 seconden.

HTTP headers worden gebruikt om de bevragingslimit naar de gebruiker te communiceren.

HTTP header Toelichting
X-Rate-Limit-Limit Geeft aan hoeveel verzoeken een applicatie mag doen per tijdsperiode
X-Rate-Limit-Remaining Geeft aan hoeveel verzoeken nog gedaan kunnen worden in de huidige tijdsperiode
X-Rate-Limit-Reset Geeft aan hoeveel seconden over zijn in de huidige tijdsperiode

API principe: Beperken van het aantal verzoeken per tijdsperiode wordt aangeraden

[rfc6585] introduceert een HTTP statuscode 429 Too Many Requests die wordt gebruikt om het overschrijden van het aantal verzoeken te melden aan de gebruiker.

API principe: Begrenzingen worden proactief gemeld

4.13 Foutafhandeling

Net als een webpagina een bruikbare foutmelding toont aan bezoekers als een fout optreedt, moet een API een bruikbare foutmelding in een bekend en verwerkbaar formaat teruggeven. De representatie van een fout is niet anders dan de representatie van een willekeurige resource alleen met een eigen set van velden.

De API moet altijd zinvolle HTTP statuscodes teruggeven. HTTP statuscodes zijn opgesplitst in twee categorieën:

Een JSON representatie van een fout moet een aantal zaken bevatten om een ontwikkelaar, beheerder en eindgebruiker te helpen:

De basis voor deze standaardformaten is [rfc7807]. Een JSON-representatie van een fout ziet er als volgt uit:

{
"type": "URI: https://content.omgevingswet.overheid.nl/id/<c>[/{categorie}]/{fout}",
"title": "Hier staat wat er is misgegaan",
"status": 401,
"detail": "Meer details over de fout staan hier",
"instance": "urn:uuid:ebd2e7f0-1b27-11e8-accf-0ed5f89f718b" // De fout-instantie  
}

Validatiefouten voor POST, PUT en PATCH verzoeken worden per veld gespecificeerd. De volledige lijst met fouten wordt in één keer teruggegeven. Dit wordt opgezet met een vast hoofdniveau en foutcode voor validatiefouten en extra foutvelden met gedetailleerde fouten per veld.

Dit ziet er dan als volgt uit:

{
"type": "https://content.omgevingswet.overheid.nl/id/<c>/ValidatieFout",
"title": "Hier staat wat er is misgegaan…",
"status": 400,
"invalid-params": [{
  "type": "https://content.omgevingswet.overheid.nl/id/<c>/validatie/Voornaam",
"name": "voornaam",
"reason": "De voornaam mag geen speciale karakters bevatten."
}, {
"type": " https://content.../<c>/fouten/validatie/Wachtwoord",
"name": "wachtwoord",
"reason": "Het wachtwoord is verplicht."
}],
"instance": "urn:uuid:4017fabc-1b28-11e8-accf-0ed5f89f718b" // De fout-instantie
}

API principe: Foutafhandeling is gestandaardiseerd

4.13.1 HTTP statuscodes

HTTP definieert een hele reeks gestandaardiseerde statuscodes die gebruikt dienen te worden door API's. Deze helpen de gebruikers van de API's bij het afhandelen van fouten.

API principe: API's passen de verplichte HTTP statuscodes toe

Samenvatting HTTP-operaties in combinatie met de primaire HTTP statuscodes:

Operatie CRUD Gehele collectie (bijvoorbeeld /resource)
Specifieke item (bijvoorbeeld /resource/\<id>)
POST Create 201 (Created), HTTP header Location met de URI van de nieuwe resource (/resource/\<id>)
405 (Method Not Allowed), 409 (Conflict) als de resource al bestaat
GET Read 200 (OK), lijst van resources. Gebruik pagineren, filteren en sorteren om het werken met grote lijsten te vereenvoudigen
200 (OK) enkele resource, 404 (Not Found) als ID niet bestaat of ongeldig is
PUT Update 405 (Method Not Allowed), behalve als het de bedoeling is om elke resource in een collectie te wijzigen of vervangen
409 als een wijziging niet mogelijk is vanwege de huidige toestand van de instantie
200 (OK) of 204 (No Content), 404 (Not Found) als ID niet bestaat of ongeldig is
PATCH Update 405 (Method Not Allowed), behalve als het de bedoeling is de gehele collectie te vervangen.
409 als een wijziging niet mogelijk is vanwege de huidige toestand van de instantie.
200 (OK) of 204 (No Content), 404 (Not Found) als ID niet bestaat of ongeldig is
DELETE Delete 405 (Method Not Allowed), behalve als het de bedoeling is de gehele collectie te verwijderen
200 (OK) of 404 (Not Found) als ID niet bestaat of ongeldig is

Hieronder een korte lijst met een beschrijving van de HTTP statuscodes die minimaal worden toegepast:

HTTP statuscode Toelichting
200 OK Reactie op een succesvolle GET, PUT, patch of DELETE. Ook geschikt voor POST die niet resulteert in een creatie
201 Created Reactie op een POST die resulteert in een creatie. Moet worden gecombineerd met een locatie-header die wijst naar de locatie van de nieuwe resource
204 No Content Reactie op een succesvol verzoek die geen inhoud zal teruggeven (zoals een DELETE)
304 Not Modified Gebruikt wanneer HTTP caching headers worden toegepast
400 Bad Request Het verzoek is onjuist, bijvoorbeeld als het verzoek (body) niet kan worden geïnterpreteerd
401 Unauthorized Als er geen of ongeldige authenticatie details worden verstrekt. Ook handig om een authenticatie-venster te tonen als de API wordt gebruikt vanuit een browser
403 Forbidden Als de authenticatie gelukt is maar de geverifieerde gebruiker geen toegangsrechten heeft voor de resource
404 Not Found Wanneer een niet-bestaande resource is opgevraagd
405 Method Not Allowed Wanneer een HTTP-methode wordt gebruikt die niet is toegestaan voor de geauthentiseerde gebruiker
406 Not Acceptable Wordt teruggegeven als het gevraagde formaat niet ondersteund wordt (onderdeel van content negotiation)
409 Conflict Het verzoek kon ik niet worden verwerkt als het gevolg van een conflict met de huidige toestand van de resource
410 Gone Geeft aan dat de resource niet langer op het eindpunt beschikbaar is. Nuttig als een overkoepelend antwoord voor oude API versies
412 Precondition Failed De preconditie die wordt gegeven door één of meer velden in de request-header, ontbraken of zijn na validatie op de server afgekeurd
415 Unsupported Media Type Als een verkeerd content-type als onderdeel van het verzoek werd meegegeven
422 Unprocessable Entity Gebruikt voor een verzoek (body) dat correct is maar dat de server niet kan verwerken
429 Too Many Requests Wanneer een aanvraag wordt afgewezen als het aantal verzoeken per tijdsperiode is overschreden
500 Internal Server Error Wanneer een onverwachte fout optreedt en het beantwoorden van het verzoek wordt verhinderd
503 Service Unavailable Wordt gebruikt als de API niet beschikbaar is (bijv. door gepland onderhoud)

5. Beveiliging

Doel van dit hoofdstuk: Hoe kan je je applicatie landschap inrichten zodat je APIs kan aanbieden. Welke componenten zijn hiervoor nodig. Hoe ga je om met opschalen, beschikbaarheid. Wat zijn afwegingen om beveiliging al dan niet toe te passen.

Voor de eerste versie van de Nederlandse API strategie bevat dit hoofdstuk alleen het onderwerp OAuth. voor toekomstige versies voorzien we mogelijk de volgende onderwerpen. wettelijke kaders en hun uitwerking in de praktijk:

Generieke beveiligingsonderwerpen:

5.1 Nederlands profiel OAuth

Deze sectie beschrijft de uitgangspunten voor het Nederlands profiel OAuth. het profiel zelf is een op zichzelfstaand document.

5.1.1 Expert advies OAuth forum standaardisatie

Het opstellen van deze standaard is voortgekomen uit het Expert advies OAuth [Expert]. Daarin wordt aangeraden eerst een nederlands profiel op stellen alvorens OAuth op de pas toe of leg uit lijst van het forum standaardisatie te plaatsen.

5.1.2 Werkingsgebied standaard

Als organisatorisch werkingsgebied wordt geadviseerd: Nederlandse overheden (Rijk, provincies, gemeenten en waterschappen) en instellingen uit de (semi-) publieke sector

5.1.3 Toepassingsgebied standaard

Als functioneel toepassingsgebied wordt voorgesteld: Het gebruik van OAuth 2.0 is verplicht voor applicaties waarbij gebruikers (resource owner) toestemming geven (impliciet of expliciet) aan een dienst (van een derde) om namens hem toegang te krijgen tot specifieke gegevens via een RESTful API. Het gaat dan om een RESTful API waar de resource owner recht tot toegang heeft.

5.1.4 OpenID connect buiten scope

de expertgroep is op 7 juli en op 22 september 2016 bijeengekomen om de standaarden, de aandachtspunten en openstaande vragen uit het voorbereidingsdossier te bespreken. Daarbij is vastgesteld dat OpenID Connect niet voor opneming op de lijst open standaarden in aanmerking komt.

5.1.5 Aansluiting op internationale standaard iGov

Het Nederlands profiel OAuth baseren we het internationale iGOV OAuth 2.0 profiel [iGOV.OAuth2] we nemen niet alle keuzes van dit internationale profiel over aangezien dit een aantal keuzes bevat die sterk leunen op de amerikaanse situatie. Het kan het best beschouwd worden als een fork waar we in ons profiel aangeven waar we afwijken. iGov heeft twee naast het OAuth profiel ook een OpenID connect profiel [iGOV.OpenID] wanneer mogelijk ook OpenID connect op de pas toe of leg uit lijst van het Forum standaardisatie komt kan dit Nederlandse profiel uitgebreid worden met een Nederlandse variant van het iGov OpenID Connect profiel. De usecase die hieronder wordt beschreven sorteerd daar al op voor.

Het Nederlands profiel OAuth is hier te vinden: https://geonovum.github.io/KP-APIs-OAuthNL/#dutch-government-assurance-profile-for-oauth-2-0

6. Bijlagen

6.1 API Principes

6.1.1 API-01: API's garanderen dat operaties "Veilig" en/of "Idempotent" zijn

Operaties van een API zijn gegarandeerd "Veilig" en/of "Idempotent" als dat zo is bepaald.

6.1.2 API-02: Toestandsinformatie wordt nooit op de server opgeslagen

De client-toestand wordt volledig bijgehouden door de client zelf.

6.1.3 API-03: Alleen standaard HTTP-operaties worden toegepast

Een RESTful API is een application programming interface die de standaard HTTP-operaties GET, PUT, POST, PATCH en DELETE gebruikt.

6.1.4 API-04: Definitie van het koppelvlak is in het Nederlands tenzij er sprake is van een officieel Engelstalig begrippenkader

Resources en de achterliggende entiteiten, velden, etc. (het informatiemodel en het externe koppelvlak) worden in het Nederlands gedefinieerd. Engels is toegestaan indien er sprake is van een officieel Engelstalig begrippenkader.

6.1.5 API-05: Resource namen zijn zelfstandige naamwoorden in het meervoud

Namen van resources zijn zelfstandige naamwoorden en altijd in het meervoud, zoals aanvragen, activiteiten, vergunningen. Ook als het om het een enkel resource betreft.

6.1.6 API-06: Relaties van geneste resources worden bij voorkeur binnen het eindpunt gecreëerd

Als een relatie alleen kan bestaan binnen een andere resource (geneste resource), wordt de relatie bij voorkeur innen het eindpunt gecreëerd. De afhankelijke resource heeft in dat geval geen eigen eindpunt

6.1.7 API-07: Resources ondersteunen bij voorkeur "lazy" en "eager" laden van relaties

Resources die een n-op-n relatie kennen ondersteunen bij voorkeur zowel het teruggeven van identificaties van gerelateerde resources (lazy loading) als het teruggeven van de resources zelf (eager loading).

6.1.8 API-08: Gelinkte resources worden expliciet en selectief mee-geladen

Gelinkte resources worden expliciet en selectief mee-geladen als onderdeel van een resource verzoek middels de expand query-parameter.

6.1.9 API-09: Indien representatie op maat wordt ondersteund, dan conform dit principe.

Het is mogelijk om een door komma's gescheiden lijst van veldennamen op te geven met de query-parameter fields om een representatie op maat te krijgen. Als niet-bestaande veldnamen worden meegegeven wordt een 400 Bad Request teruggegeven.

6.1.10 API-10: Acties die niet passen in het CRUD model worden een sub-resource

"Acties die niet passen in het CRUD model worden op de volgende manieren opgelost:

  • Behandel een actie als een sub-resource.

  • Alleen in uitzonderlijke gevallen wordt een actie met een eigen eindpunt opgelost."

6.1.11 API-11: De verbinding is ALTIJD versleuteld met minimaal TLS V1.2

De verbinding is ALTIJD versleuteld op basis van minimaal TLS V1.2. Geen uitzonderingen, dus overal en altijd. In het geval van toegangsbeperking of doelbinding wordt tweezijdig TLS toegepast. Doordat de verbinding altijd is versleuteld maakt het authenticatiemechanisme eenvoudiger. Hierdoor wordt het mogelijk om eenvoudige toegangstokens te gebruiken in plaats van toegangstokens met encryptie.

6.1.12 API-12: API's zijn bij voorkeur alleen bruikbaar met behulp van een API-key

Voor alle API's wordt bij voorkeur minimaal een registratie inclusief acceptatie van de fair use voorwaarden vereist. Op basis hiervan zal dan een API-key wordt uitgegeven.

6.1.13 API-13: Tokens worden niet gebruikt in query parameters

Er is een inherent beveiligingsprobleem bij het gebruik van een query parameter voor tokens omdat de meeste webservers queryparameters in de server logs wegschrijven.

6.1.14 API-14: Autorisatie is waar nodig gebaseerd op OAuth 2.0

Een REST API mag geen state hebben. Elk verzoek moet daarom zijn voorzien van een token. OAuth 2.0 is hiervoor de voorgeschreven standaard, hoofstuk Beveiliging bevat meer informatie.

6.1.15 API-15: Authenticatie voor API's met toegangsbeperking of doelbinding is gebaseerd op PKIoverheid

In het geval van API's met toegangsbeperking of doelbinding zal er aanvullend sprake zijn van authenticatie op basis PKIoverheid certificaten en tweezijdig TLS.

6.1.16 API-16: Documentatie is gebaseerd op OAS 3.0 of hoger

Specificaties (documentatie) is beschikbaar als Open API Specification (OAS) V3.0 of hoger.

6.1.17 API-17: Documentatie is in het Nederlands tenzij er sprake is van bestaande documentatie in het Engels of er sprake is van een officieel Engelstalig begrippenkader

De voertaal voor de API's is Nederlands. Het is wel toegestaan om te verwijzen naar bestaande documentatie is het Engels en als er sprake is van een officieel Engelstalig begrippenkader.

6.1.18 API-18: Wijzigingen worden gepubliceerd met een uitfaseringschema

Koppelvlak wijzigingen worden met bijbehorende planning op een publiek toegankelijke blog als changelog bekendgemaakt en via een mailinglijst.

6.1.19 API-19: De overgangsperiode bij een nieuwe API versie is maximaal 1 jaar

Oude en nieuwe versies (max. 3) van een API worden voor een beperkte overgangsperiode (1 jaar) naast elkaar aangeboden.

6.1.20 API-20: Alleen het major versienummer is onderdeel van de URI

In de URI wordt alleen het major versienummer opgenomen. Minor versienummer en patch versienummer worden in de header van het bericht zelf opgenomen. Het uitgangspunt dat hierbij wordt gehanteerd is dat minor versies en patches geen impact hebben op bestaande code, maar major versies wel.

6.1.21 API-21 Gebruikers van een ‘deprecated' API worden actief gewaarschuwd

Met een Warning response-header in alle responses van de oude API's worden gebruikers gewaarschuwd voor de aanstaande uitfasering.

6.1.22 API-22: JSON first - API's ontvangen en versturen JSON

API's ontvangen en versturen JSON.

6.1.23 API-23: API's zijn optioneel voorzien van een JSON Schema

API's ondersteunen JSON Schema (<http: json-schema.org),="">zodat validatie mogelijk (optioneel) is en vereenvoudigd wordt.

6.1.24 API-24: Content negotiation wordt volledig ondersteund

Andere representaties zoals XML en RDF worden naast JSON via het standaard HTTP content negotiation mechanisme ondersteund. Als het gewenste formaat niet geleverd kan worden zal er een 406 Not Acceptable worden teruggegeven.

6.1.25 API-25: API's controleren dat de Content-Type header is ingesteld

Er wordt gecontroleerd of het Content-Type header is ingesteld op application/json of andere ondersteunde content types, anders wordt HTTP statuscode 415 Unsupported Media Type geretourneerd.

6.1.26 API-26: Woorden in veldnamen zijn gedefinieerd in camelCase

Een veldnaam begint met kleine letters (eerste woord) en ieder opvolgend woord begint met een hoofdletter.

6.1.27 API-27: Pretty print is standaard uitgeschakeld

Het uitgangspunt is dat REST clients en browsers (al dan niet met extensies) JSON netjes geformatteerd kunnen weergeven.

6.1.28 API-28: Een JSON-response heeft geen omhullende envelop

Er worden standaard geen enveloppen toegepast.

6.1.29 API-29: API's ondersteunen JSON gecodeerde POST, PUT en PATCH payloads

API's ondersteunen minimaal JSON gecodeerde POST, PUT en PATCH payloads. Encoded form data (application/x-www-form-urlencoded) wordt niet ondersteund.

6.1.30 API-30: Filter query-parameters zijn gelijk aan de velden waarop gefilterd kan worden

Gebruik unieke query-parameters die gelijk zijn aan de velden waarop gefilterd kan worden.

6.1.31 API-31: Voor sorteren wordt de query-parameter sorteer gebruikt

De generieke query-parameter sorteer wordt gebruikt voor het specificeren van door komma's gescheiden velden waarop gesorteerd moet worden. Door een minteken (-) voor de veldnaam te zetten wordt het veld in aflopende sorteervolgorde gesorteerd.

6.1.32 API-32: Voor vrije-tekst zoeken wordt een query-parameter zoek gebruikt

API's die vrije-tekst zoeken ondersteunen doen dit middels de query-parameter zoek.

6.1.33 API-33: API's die vrije-tekst zoeken ondersteunen kunnen overweg met twee soorten wildcard karakters: * en ?

API's die vrije-tekst zoeken ondersteunen kunnen overweg met twee soorten wildcard karakters:

  • * Komt overeen met nul of meer (niet-spatie) karakters

  • ? Komt precies overeen met één (niet-spatie) karakter

6.1.34 API-34: GEO API's ontvangen en versturen bij voorkeur GeoJSON

Voor GEO API's wordt bij voorkeur de standaard GeoJSON (RFC-7946) gebruikt.

6.1.35 API-35: GeoJSON is onderdeel van de embedded resource in de JSON response

Als een JSON (application/json) response een geometrie bevat, dan wordt deze geometrie op dezelfde manier teruggegeven als het geometry object van GeoJSON (RFC-7946):

{
 "type": "Point",
 "coordinates": [125.6, 10.1]
}

6.1.36 API-36: Voor GEO queries is een POST end-point beschikbaar

Geometrische queries worden in een POST naar een apart endpoint verzonden.

6.1.37 API-37: POST end-points zijn uitbreidbaar voor gecombineerde vragen

De geometrie is uitbreidbaar met andere properties voor gecombineerde queries.

6.1.38 API-38: Resultaten van een globale geometrische zoekvraag worden in de relevante geometrische context geplaatst

In het geval van een globale zoekvraag /api/v1/_zoek is het noodzakelijk om de resultaten in een relevante context te plaatsen, omdat resultaten van verschillende collecties door elkaar teruggegeven worden. Met de property type kan in enkelvoud de naam van de collectie waar het resultaat toe behoort uitgedrukt worden.

6.1.39 API-39: Het voorkeur-coördinatenstelsels (CRS) is ETRS89, maar het CRS wordt niet impliciet geselecteerd

Algemeen gebruik van het Europese ETRS89 coördinatenstelsel (CRS) heeft sterk de voorkeur, maar dit wordt niet door API's afgedwongen als de "default". Derhalve moet het te gebruiken CRS in elke aanroep expliciet worden opgegeven.

6.1.40 API-40: Het coördinatenstelsel (CRS) van de vraag en het antwoord wordt in de header meegestuurd

Het gekozen coördinatenstelsel (CRS) voor zowel de vraag als het antwoord worden meegestuurd als onderdeel van de request-header en de response-header. Bij het ontbreken van deze headers wordt 412 Precondition Failed teruggegeven. Hiermee wordt voorkomen dat per abuis met het verkeerde CRS wordt gewerkt

6.1.41 API-41: Het gewenste coördinatenstelsel wordt op basis van content negotiation overeengekomen

Het gewenste CRS voor de geometrie in het antwoord (response body) wordt aangeduid met een Accept-Crs header. Als het gewenste CRS niet geleverd kan worden zal er een 406 Not Acceptable worden teruggegeven.

6.1.42 API-42: Paginering wordt gerealiseerd op basis van JSON+HAL bij media type: application/hal+json

Aan de representatie worden twee gereserveerde velden _links (verplicht) en _embedded (optioneel) toegevoegd. Daarnaast wordt paginerings-metadata als HTTP headers meegegeven.

6.1.43 API-43: Waar relevant wordt caching toegepast

Voor caching wordt gebruikt van de HTTP standaard caching mechanismes door het toevoegen van een aantal extra uitgaande HTTP headers (ETag of Last-Modified) en functionaliteit om te bepalen of een aantal specifieke inkomende HTTP headers (If-None-Match of If-Modified-Since).

6.1.44 API-44: Beperken van het aantal verzoeken per tijdsperiode wordt aangeraden

Aangeraden worden om het aantal verzoeken per tijdsperiode te beperken om overbelasting van servers te voorkomen om een hoog serviceniveau te garanderen.

6.1.45 API-45: Begrenzingen worden proactief gemeld

Gebruik X-Rate-Limit headers om limieten aan de gebruiker te communiceren en HTTP statuscode 429 Too Many Requests als de limieten overschreden worden.

6.1.46 API-46: Foutafhandeling is gestandaardiseerd

API's ondersteunen de gestandaardiseerde foutmeldingen van de HTTP-statuscodes 400 en 500 reeks inclusief een verwerkbare JSON representatie in lijn met RFC7807.

6.1.47 API-47: API's passen de verplichte HTTP-statuscodes toe

De volgende http-statuscodes worden minimaal toegepast: 200, 201, 204, 304, 400, 401, 403, 405, 406, 409, 410, 415, 422, 429, 500, 503.

6.1.48 API-48: API-endpoints mogen géén trailing slashes bevatten

URIs die gebruikt worden om collecties van resources of individuele resources op te vragen eindigen nooit met een trailing slash. Een resource leeft op één plek/path. Resource paths eindigen zonder slash.

6.1.49 API-49: Gebruik "publieke" API-Key

In JavaScript dient alleen gebruik te worden gemaakt van een zogenaamde "restricted" API-key. Dit is API-key die gekoppeld is aan specifieke kenmerken van de aanroeper (web-app, mobile-app), waaronder een clientId en/of verwijzer-URL.

6.1.50 API-50: Controleer toegang en gebruik CORS-header

Controleer eerst het domein van de inkomende aanvraag en genereer de response-header afhankelijk van of dit domein verzoeken mag verzenden of niet (whitelist). In dat geval wordt alleen dit specifieke domein aan de response-header Access-Control-Allow-Origin toegevoegd.

**LET OP: Het is technisch mogelijk om in de Access-Control-Allow-Origin responsheader een wildcard ("*") terug geven en zo alle bronnen toe te staan. Dit is een onveilige praktijk!**

6.1.51 API-51: OAS via basis-URI beschikbaar in JSON-formaat

Om te zorgen dat de actuele documentatie altijd publiekelijk toegankelijk is, is het advies om de inhoud van de Open API Specification op het "root endpoint" van de API beschikbaar te maken in JSON-formaat:

https://service.omgevingswet.overheid.nl/publiek/catalogus/api/raadplegen/v1

Maakt de OAS behorend bij v1 van deze API beschikbaar.

Hiermee wordt een unieke plek (die altijd synchroon loopt met de features die de API biedt) gekoppeld aan de actuele documentatie.

6.2 Architectuur

Let op: Dit is het hoofdstuk Architectuur in wording.
De onderwerpen in het hoofdstuk staan nog ter discussie, en ze staan er nog niet met de bedoeling om normatief en/of best-practice te zijn.

Dit hoofdstuk gaat in op de vraag: Hoe kan je je applicatie landschap inrichten zodat je APIs kan aanbieden. Welke componenten zijn hiervoor nodig. Hoe ga je om met opschalen, beschikbaarheid. Wat zijn afwegingen om beveiliging al dan niet toe te passen.

6.2.1 Inleiding

Doel van dit hoofdstuk is om een hoog niveau overzicht te geven van relevante onderdelen en concepten en hun samenhang in een op (REST) API gebaseerde architectuur waarbij gebruik gemaakt wordt van (REST) API's als interface voor de aangeboden (gegevens)diensten. Specifiek voor REST API's is dat deze 'Resource' gericht zijn en een uniforme manier bieden om resources te lezen, wijzigen, toevoegen of verwijderen.

Figuur 1: De plaats van API's bij aanbod en gebruik van (gegevens)diensten;

Figuur 1 toont de plaats van API's in de gegevensuitwisseling en relevante onderwerpen in deze context. Bij de Dienst afnemer speelt het gebruik van API's, bij de Dienst aanbieder speelt het aanbieden van API's.

In dit hoofdstuk wordt specifiek ingegaan op de 'aanbod kant': het onderdeel 'Diensten toegang' in het schema.

6.2.2 Diensten toegang & API management

Een diensten aanbieder ontsluit zijn diensten middels API's aan een diensten afnemer; om deze API's gecontroleerd aan te bieden is management en beheer van de API's van de organisatie noodzakelijk.

Een organisatie heeft verschillende soorten API's:

Open API's: voor ontsluiten van diensten zonder toegangsbeperking bv open data.

Gesloten API's: voor ontsluiten van diensten met toegangsbeperking bv persoonsgegevens en vertrouwelijke gegevens of diensten voor specifieke partijen.

Figuur 2 beschrijft vanuit het perspectief van een overheidsorganisatie als dienstaanbieder de onderwerpen die aandacht vragen in een op API's gebaseerde architectuur. Hieronder worden deze onderwerpen uitgebreider toegelicht.

Figuur 2: Onderdelen van een API architectuur - Algemeen overzicht

API-Gateway

Dit is het runtime onderdeel dat op de organisatiegrens van de diensten aanbieder de API-aanroepen ontvangt.

Throttling
Het beschermen van de dienst tegen overbelasting door de hoeveelheid aanvragen te beperken. Een aandachtspunt hierbij is de SLA afspraak die mogelijk hierbij van toepassing is en dat kritische bedrijfsprocessen de vereiste beschikbaarheid verkrijgen of behouden;

Authenticatie
Het vaststellen van de identiteit van de afnemer van de API;
(Zie ook : https://www.noraonline.nl/wiki/Identity_%26_Access_Management)

Autorisatie
Het bepalen of de afnemer recht heeft tot gebruik van de API;

Routering
Dit betreft het routeren van de API-aanroep naar de juiste achterliggende applicatie;

Logging
Dit betreft het loggen van API aanroepen van diensten afnemers;

API Management

Dit onderdeel betreft het beheren van de API's van de dienstenaanbieders. Op basis van de registratie van API's kan de life-cycle van de API beheerd worden, de runtime omgeving worden ingericht en partners en developers worden voorzien van informatie over het gebruik van de API's;

Toegang De dienstaanbieder administreert wie toegang heeft tot welke API. De runtime omgeving (API-gateway) wordt geconfigureerd volgens de gewenste toegangsregels om de toegang te bewaken;

API Meta Data De dienstaanbieder administreert welke API's door de onderneming aangeboden worden. Dit betreft zowel open API's als gesloten API's;

API Life Cycle De dienstaanbieder beheert de levenscyclus van de API's (design, test, productie, afvoer);

Monitoring De dienstaanbieder monitort beschikbaarheid en gebruik van de API's;

Developer Portal

Het Developer portal ondersteunt de ontwikkelaar bij het gebruik van API's. Bijvoorbeeld door middel van documentatie, voorbeelden, API-register (overzicht van alle beschikbare API's), sandbox voor experimenten en ook 'onboarding' / aanmelden voor toegang en developer account beheer.

Applicaties Afnemer & Applicaties Aanbieder

De applicaties van de afnemer maken gebruik van de diensten van de dienstenaanbieder door het aanroepen van API's. De applicaties van de aanbieder leveren de diensten door het aanbieden van API's.

Identity Management

In gevallen waar de identiteit van de dienstenaanvrager van belang is en onderdeel van de toegangs controle en gebruiksmonitoring, is de relatie met het identity management systeem van de organisatie relevant.
(Zie ook : https://www.noraonline.nl/wiki/Begrippen_IAM)

Punten voor verdere uitwerking in vervolgtrajecten: -Certificering van (mobile) apps / afnemer applicaties -Afspraken / standaarden 'Overheid 2 Overheid' (gesloten) API's -Centrale voorzieningen in de GDI mbt API's bv API-register

Website:

De impact van API's op de architectuur van alle organisaties die hier serieus mee aan de slag gaan is groot, net als de behoefte aan kennis op dit gebied. De werkgroep Architectuur buigt zich over vragen rond de volgende onderwerpen: de impact van het gebruik van API’s op de gehele informatievoorziening van een organisatie, de kennisopbouw over benodigde architectuur in overheidsorganisaties en het overzicht en sturing van gewenste beweging naar het gebruiken van data in plaats van het bezitten van data.

Sec:

-beschrijving van de impact van (gebruiken van ) API’s op de eigen informatievoorziening (vanuit bestaande use-cases)

-Werken aan kennis opbouw over de benodigde architectuur voor het kunnen werken met API’s

-sturing en richting geven aan de noodzakelijke beweging van data ‘hebben’ naar data ‘gebruiken’ bij het werken met API’s.

  1. De GitHub tekst over REST API architectuur wordt een tekst over architectuurthema’s (beveiliging, logging, semantiek, doelbinding etc) om organisaties en mensen die zich aan het informeren zijn over REST API’s ’s om hen te helpen bij beslissingsondersteuning

  2. De architectuur tekst in GitHub wordt nog geen referentie architectuur: daarvoor zijn API , methodieken, technieken, standaarden etc op dit moment in 2018 nog teveel in ontwikkeling en onvoldoende stabiel

  3. Daar waar mogelijk meer stabiele architectuur elementen worden voorzien, kunnen deze van bv principes, begrippen, bouwstenen, standaarden, wettelijke grondslagen, beleid en kaders voorzien. Dit is een eerste stap richting in een nog uit te werken referentie architectuur

  4. Hoofdmoot van het stuk zal zijn om stapsgewijs voor te sorteren op die elementen, methodieken en technieken die mogelijk stabiel genoeg kunnen gaan worden

  5. Bijvoorbeeld rond NLX: <https: nlx.io="" about="">

  6. Daarmee geeft de werkgroep Architectuur API inrichting van de NORA Applicatielaag vanuit API persperctief: <https: www.noraonline.nl="" wiki="" applicatielaag="">

De werkgroep leden hebben in november 2018 gekozen voor de volgende thematische indeling:

6.2.3 Beveiliging

6.2.4 Autorisatie

6.2.5 Semantiek

Noemen: ontwikkelingen op het gebied van Linked (open) Data, stelsel van overheidsgegevens en link: <https: www.noraonline.nl="" wiki="" semantiek="">

6.2.6 Metadata

?Noemen: Toepassingsprofiel Metadata Rijk, TMLO? Relatie leggen. <https: www.noraonline.nl="" wiki="" metagegevens_duurzame_toegankelijkheid="">

6.2.7 Interoperabiliteit

?Benadrukken voordelen voor interoperabiliteit. <https: www.noraonline.nl="" wiki="" interoperabiliteit="">

6.2.8 Patronen

Principes ondersteunen het proces om te komen tot nauwkeurige afbakening en definities van API’s van eenzelfde type. Daarnaast bevorderen zij over de verschillende bronnen heen het eenduidig gebruik van API’s voor overeenkomstige concepten. In de visualisatie hieronder is de structuur van de principes zichtbaar. Het blauw gekleurde principe is overkoepelend. Verder passen de overige principes binnen verschillende architectuurpatronen van API’s die ook in onderstaand figuur wordt weergegeven (zie oranje gekleurde principes).

Figuur 1 Structuur tussen de principes.

6.2.8.1 Herbruikbaarheid

API-01: Gepubliceerde API’s zijn herbruikbaar API’s die worden ontwikkeld moeten in lijn zijn met de opgestelde principes, hierdoor ontstaat er uniformiteit. Voorafgaand aan publicatie voor hergebruik toetst Forum Standaardisatie dit.

  • Voor feitelijk hergebruik kan plaatsvinden moet een onpartijdig oordeel over de kwaliteit van de API uitgesproken worden. Forum Standaardisatie kan die onpartijdige toets uitvoeren op de gerealiseerde API's.
  • Consumer wil bij hergebruik weten wat de kwaliteit is en de zekerheid hebben dat het werkt en beheerd wordt.
  • De provider van een API toont de kwaliteit van de API aan bij publicatie.
  • Door hergebruik van eenmalig ontwikkelde API's kan een softwareleverancier zich juist focussen op het bieden van toegevoegde waarde in de functionele ondersteuning van processen in taakgebieden. Het doel is om een situatie te bereiken waarin API's hergebruikt en gedeeld worden (generiek inzetbaar).
  • Enkel API’s worden gemaakt waarvoor nog geen API aanwezig is, waardoor er niet méér API's gemaakt worden dan nodig zijn.
6.2.8.2 Patroon ‘Bijhouden’

Een levens- of systeemgebeurtenis (zoals een geboorte of het verstrijken van tijd) triggert een proces. Dit proces leidt (in veel gevallen) tot het bijwerken van de data in de registratie van de bronhouder. De volgende principes worden benoemd binnen dit patroon.

API-01: Een gebeurtenis zorgt voor een proces waarin een bijhoudingstaak zit voor de bronhouder Bronhouders hebben de verantwoordelijkheid om hun bronregistratie actueel te houden. Gebeurtenissen die effect hebben op de data in de bronregistratie triggeren een bijhoudingstaak.

API-02: Een API van type ‘POST’ faciliteert het bijhouden van data in de bronregistratie. Restful API’s op basis van JSON van het type ‘POST’ worden toegepast om data te actualiseren in een registratie.

6.2.8.3 Patroon ‘Afnemen’

Een systeemgebeurtenis (zoals een bijhouding van de bronhouder) triggert een proces. Dit proces leidt (in veel gevallen) tot het notificeren van gebeurtenissen richting (eventuele) afnemers. Afnemers bepalen zelf of zij op basis van ontvangen notificaties data op gaan halen. De volgende principes worden benoemd binnen dit patroon.

API-01: Een API in de categorie Notificeren faciliteert het melden van gebeurtenissen aan een afnemer.
Een notificatie is een melding van een gebeurtenis die een procestrigger vormt. Een gebeurtenis kan een wijziging in de gegevens van de bronhouder tot gevolg hebben en daarom kan het zinvol zijn voor een afnemer hierover genotificeerd te worden. Gebeurtenissen worden te allen tijde door bronhouder gecommuniceerd richting een broker (bijvoorbeeld ESB/API-Gateway) zo kort mogelijk na het optreden van de gebeurtenis, ongeacht of er afnemers zijn. Dit is de verantwoordelijkheid van de bronhouder. Indien er een afnemer is brengt de notificatie de afnemer op de hoogte van de gebeurtenis. Dit triggert bij de afnemer een proces: De afnemer is aan zet om te oordelen wat de passende vervolgacties zijn bij het ontvangen van de notificatie. Een notificatie bevat geen content anders dan identificerende (functionele) gegevens. Notificaties worden toegezonden aan afnemers die middels afnemerindicaties hebben aangegeven notificaties te willen ontvangen.

API-02: Een API in de categorie Notificeren faciliteert het melden van gebeurtenissen aan een afnemer.
Afnemers die via API Notificeren gegevens willen ontvangen nemen op het niveau van een resource (dus niet instelbaar op een specifiek data-object) in de breedte van het geografische verzorgingsgebied gebeurtenissen af. Uitzondering: Voor de BRP (en eventuele registraties of data waar privacy op rust) is hier gelet op de privacywetgeving een uitzondering op. Voor het afnemen van personen uit de BRP dient per persoon een specifieke afnemerindicatie geplaatst te zijn door de afnemer, in lijn met zijn doelbinding. Geadviseerd wordt afnemerindicaties te plaatsen door het uitwisselen van het 'BSN' en niet door het uitwisselen van een technische sleutel.

API-03: Notificaties zijn gebaseerd op de informatiebehoefte van bedrijfsprocessen. Afhankelijk van de informatiebehoefte bij afnemers voor het triggeren van bedrijfsprocessen worden notificaties onderkend. In grote lijnen komt dit overeen met de gebeurtenissen die in de ontwerpdocumenten of berichtencatalogi van bronregistraties zijn onderkend.

API-04: Een API in de categorie Opvragen faciliteert het uitwisselen van gegevens op basis van een vraag-antwoord constructie. De categorie Opvragen wordt gebruikt voor het op afroep verkrijgen van gegevens uit een bron, of diensten vanuit een dienstenaanbieder via synchrone calls. Naargelang de informatiebehoefte van de afnemer kunnen API’s in de categorie Opvragen worden ingericht voor het verstrekken van gegevens (voor zowel raadplegen, zoeken als massaal bevragen t.b.v. synchroniseren) of het aanroepen van een dienst. Het informatiemodel van de bronhouder is leidend bij het ophalen van gegevens.

API-05: Een vraag/antwoord API ondersteunt het opvragen van een concreet afgebakende set gegevens. Elke response van de categorie Opvragen omvat maximaal (afhankelijk van autorisatie, zie design decision BRP API) de attributen, relaties en de identificerende gegevens van de gerelateerde, maar niet de gerelateerde resources in zijn geheel. Het verkrijgen van de gerelateerde resources vereist het stellen van een nieuwe vraag (nieuwe API-call uit categorie Opvragen).

  • De bronhouder is verantwoordelijk voor de autorisatie op organisatie-niveau.
  • De provider bepaalt het maximum aantal responses en niet de consumer. De API geeft een foutmelding wanneer er teveel resultaten zijn op de vraag.
  • De afnemer kent de doelbinding van het verzoek en stuurt de aanduiding van de doelbinding mee in de call.
6.2.8.4 Patroon ‘Terugmelden’

Een systeemgebeurtenis (zoals het verwerken van een antwoord door de afnemer) triggert een proces. Dit proces kan leiden tot het verrichten van een terugmelding, aangezien de afnemer twijfelt aan de juistheid van de gegevens. De afnemer signaleert dit richting bronhouder.

API-01: Een afnemer verricht een terugmelding bij gerede twijfel aan de juistheid van de gegevens. Gegevens in bronregistraties moeten actueel en betrouwbaar zijn. Terugmelden is één van de instrumenten om de kwaliteit van registraties te borgen. Iedere terugmelding draagt bij aan het verbeteren van een overheidsadministratie. Afnemers van de registraties hebben daarom de wettelijke plicht om mogelijk onjuiste gegevens te melden als het gaat om authentieke gegevens. Voor niet-authentieke gegevens geldt die verplichting niet. Het proces van terugmelden zorgt ervoor dat de fout in de registratie wordt gesignaleerd en na onderzoek door de bronhouder zo nodig wordt hersteld, waardoor alle afnemers vervolgens het juiste gegeven kunnen gebruiken. Het proces van Terugmelden onderscheidt 3 fasen:

  • De signalering van mogelijk onjuiste gegevens door de afnemer of de betrokkene (correctierecht).
  • Het in onderzoek nemen van het gemelde gegeven door de bronhouder.
  • De correctie en beschikbaarstelling van het gemelde gegeven aan de afnemer die het gegeven had gesignaleerd en afnemers die zijn geabonneerd op wijzigingen van de desbetreffende gegevens (dit behoort weer tot het patroon ‘Bijhouden’).

De verschillende patronen zijn aan elkaar gerelateerd en hebben een duidelijke afhankelijkheid. Dit is in onderstaand figuur afgebeeld. Per patroon is ook aangegeven hoe gebeurtenissen, processen en datastromen zich tot elkaar verhouden.

Figuur 2 Visualisatie patronen (gelaagdheid tussen real life, proces en data).

6.2.9 Componenten

Hamvraag: zijn REST API’s bouwstenen (architectuur component)? Behandelen: op welke wijze API’s eenduidig zijn te beschrijven en vindbaar te maken zijn. Wat kunnen we (concreet) van hieruit aan richtinggevende normen/ regels voor API Register’s meegeven? Wie hebben er een use case rond een API register?

6.2.10 Begrippen

Noemen/ overnemen begrippen uit document BFS over API’s. Proberen een steeds meer gestandaardiseerd begrippenkader voor REST API’s neer te zetten

6.2.11 Standaarden

Updaten en overnemen lijst met API standaarden uit het document BFS (Lancelot Schellevis)

6.2.12 Use cases

Iig: use case Drechtsteden. Overige? Let wel: use cases zijn in dit stadium het uitgangspunt

6.2.13 Architectuur bijlagen

Bijgevoegd document:

Werkgroep Architectuur\Werkgroep_API_Architectuur Draft D[29148].pdf

A. Referenties

A.1 Normatieve referenties

[Expert]
Expertadvies OAuth 2.0. P. Dam. Forum Standaardisatie. 24 februari 2017. URL: https://www.forumstandaardisatie.nl/sites/bfs/files/Expertadvies%20OAuth%202.0.pdf
[HAL]
HAL - Hypertext Application Language. Mike Kelly. 2013-09-18. URL: http://stateless.co/hal_specification.html
[iGOV.OAuth2]
International Government Assurance Profile (iGov) for OAuth 2.0. J. Richer, M. Varley, P. Grassi. OpenID foundation. October 5 2018. URL: https://openid.net/specs/openid-igov-oauth2-1_0.html
[iGOV.OpenID]
International Government Assurance Profile (iGov) for OpenID Connect 1.0 - draft 3. M. Varley, P. Grassi. OpenID foundation. October 5 2018. URL: https://openid.net/specs/openid-igov-openid-connect-1_0.html
[rfc6585]
Additional HTTP Status Codes. M. Nottingham; R. Fielding. IETF. April 2012. Proposed Standard. URL: https://tools.ietf.org/html/rfc6585
[rfc7807]
Problem Details for HTTP APIs. M. Nottingham; E. Wilde. IETF. March 2016. Proposed Standard. URL: https://tools.ietf.org/html/rfc7807
[rfc8142]
GeoJSON Text Sequences. S. Gillies. IETF. April 2017. Proposed Standard. URL: https://tools.ietf.org/html/rfc8142