VNG-Realisatie/ODS-Open-Raadsinformatie

Endpoint foor Feed toevoegen (versiebeheer, wijzigingen)

joepio opened this issue · 4 comments

REST (REpresentational State Transfer) is ontworpen om de huidige staat van objecten over de lijn te communiceren. Voor de meeste hergebruikers, die simpelweg resources willen weergeven, volstaat dit. Helaas is dit in sommige situaties niet voldoende. Voor een aantal usecases is een systeem nodig waar de wijzigingen opvraagbaar zijn, in plaats van de huidige staat. Ik wil graag een aantal situaties toelichten waarin REST tekort schiet en waar we dus iets anders nodig zouden kunnen hebben:

Het bijhouden van een (volledige) kopie

Sommige systemen hebben een (deel van) de data nodig voor interne opslag. Hiervoor is synchronisatie nodig. Om te illustreren waarom dit lastig gaat over een traditionele REST API: bij Open Raadsinformatie vragen we elke nacht aan alle raadsinformatiesystemen alle vergaderingen op van de afgelopen maand en de komende maand. Deze vergelijken we met de data die we al hebben. Deze aanpak heeft een aantal nadelen:

  • We missen wijzigingen die meer dan 30 dagen in het verleden / toekomst liggen.
  • Het vraagt veel bandbreedte en rekenkracht - zowel aan de data aanbieder server als de hergebruiker.
  • We hebben logica nodig om de wijzigingen te detecteren en om te voorkomen dat er resources (onterecht) dubbel worden aangemaakt.

Het snel ontvangen van updates

Sommige systemen willen weten wanneer iets veranderd. Denk bijvoorbeeld aan een mail notification systeem zoals in 1848.nl, waar meldingen worden verstuurd wanneer een item met een bepaalde zoekterm is toegevoegd. Ook dit is lastig te realiseren door alleen gebruik te maken van een REST API: als je minder dan 5 minuten vertraging wil hebben, moet je iedere 5 minuten pullen. Dat worden met een naïeve implementatie al snel zware requests.

Voorstel

Ik stel voor dat de Open Raadsinformatie API een endpoint specificeert waarin een hergebruiker een lijst van wijzigingen (events / deltas / feed items / activities) kan opvragen. Een goed gedocumenteerde en veel geïmplementeerde specificatie die kan volstaan, is de W3C Activity Streams standaard. Het is relatief eenvoudig om hier een minimale implementatie voor te schrijven. De leverancier kan een lijst met URLs van items teruggeven op een bepaald endpoint (/feed, bijvoorbeeld). Het client systeem kan vervolgens middels losse requests de inhoud van de aangemaakt / gewijzigde items ophalen, of de verwijderde items zelf verwijderen.

Ik heb tevens een alternatief, mogelijk iets ingrijpender voorstel: linked-delta's gebruiken. Dit is een zeer eenvoudig model om wijzigingen in een RDF graaf mee te communiceren. We gebruiken linked-delta's op dit moment in Open Raadsinformatie als format in een event store (in Kafka), waarin alle wijzigingen in de data staan. Deze wijzigingen worden vervolgens uitgelezen door diverse systemen, zoals ori_api. Door de linked-delta's uit te lezen, kunnen vershillende representaties van de huidige data kan worden gemaakt. Dit kan een REST api zijn, een zoekmachine, een SQL database, een Triple Store met SPARQL mogelijkheden, een archief of iets anders. Deze opzet wordt ook wel Command Query Responsibility Segregation (CQRS) met Event Sourcing genoemd. Deze aanpak heeft een aantal unieke eigenschappen:

  • De Events (bijv. linked-delta's) kunnen worden uitgelezen / afgespeeld door diverse systemen, waardoor je uiteenlopende query mogelijkheden kan ondersteunen
  • Er is altijd een krachtig log + audit trail van alle wijzigingen, wat helpt bij debugging als bij vingers wijzen van foute data
  • Versiebeheer + full history playback is eenvoudig te implementeren

Als RIS leveranciers alleen maar aan dit endpoint zouden voldoen, kunnen we zeer eenvoudig alle data synchroniseren met ORI. Vervolgens kunnen leveranciers (en de burgers / raadsleden / ambtenaren) genieten van alle extra functionaliteiten die nu mogelijk zijn: het zoeken op ORI, de WaarOverheid locatie features, een Thema classifier, een open API om apps mee te bouwen...

Mijn verwachting is dat het implementeren van een dergelijke linked delta feed relatief eenvoudig is om te implementeren door leveranciers. Met iBabs gaan we het in ieder geval verkennen.

Wat leuk is aan deze linked-delta's, is dat het in principe kan werken met ieder model, zolang het maar voldoet aan enkele RDF constraints:

  • Iedere resource moet een URL hebben (die, als het even kan, ook resolvebaar is)
  • Eigenschappen (de keys van een object) moeten ook een URL hebben (zoals URLs van de ORI standaard)
  • Waarden zijn altijd OF URI's OF strings met eventueel een datatype erachter

In de praktijk zijn deze eisen niet zeer beperkend, maar door ze te volgen wordt er wel veel mogelijk gemaakt.

Misschien dat dit alles nu als een wat warrig verhaal klinkt. Ik kom het graag binnenkort eens verder toelichten.

Een paar slimme mensen wezen mij op nog een alternatief: RDF-Delta. De bovengenoemde constraints tellen dan ook. Een voordeel van deze spec is dat deze ook al de Logs heeft gestandaardiseerd.

Heb mij afgelopen maanden nog wat meer in deze materie gestort, en diverse systemen vergeleken. Hier te lezen.

Een jaar later, en ik heb een aantal van mijn ideetjes wat verder ontwikkeld. Ik heb vooral gewerkt aan de Atomic Commits specificatie, een wijzigingen model dat:

  • Wijzigingen in data machine-leesbaar uitdrukt
  • Cryptografie gebruikt om authenticiteit te bewijzen (dus zien wie wat heeft gemaakt)
  • Type-safety hierin mogelijk maakt, terwijl het compatible is met JSON en RDF

Dit zou als model kunnen worden gebruikt om arbitraire resources (vergaderingen, moties, documenten, politici) in-sync te houden, en versies bij te houden. Om dit te implementeren als RIS hoeven er geen nieuwe endpoints of querymogelijkheden worden gebouwd - alleen een systeem dat de Commits (wijzigingen) genereert wanneer een object veranderd of wordt aangemaakt. Deze moeten vervolgens worden gestuurd naar een (of meerdere) server(s) die een /commit endpoint hebben geimplementeerd. Dit zou een elegante, schaalbare en decentrale architectuur zijn die kan worden gebruikt voor een groeiend aantal typen resources.

Als ik nu de Open-Raadsinformatie software opnieuw zou maken, zou ik gebruik maken van dit model - het zou het geheel een stuk eenvoudiger en sneller maken. Een tweetal implementaties van Atomic Data zijn onder een open source licentie beschikbaar voor typescript / javascript en rust.

Mocht er ooit een v2 van de API komen, dan zou ik voorstellen om Atomic Commits te overwegen als abstractie voor wijzigingen.