Denne side beskriver hvordan du som anvender af Datafordeleren kan oprette forbindelse til at abonnere på hændelser for et givent register. 

Der tages udgangspunkt i at abonnere på hændelser for et enkelt register, herunder BBR. Processen vil være den samme for registrene, registernavnet skal bare udskiftes til det register du ønsker at abonnere på hændelser for.

Læs mere om hændelser.


Sideinformation



Andre metoder til vedligeholdelse af kopiregister

Ønsker du ikke at bruge hændelser, kan du benytte deltadownloads der kommer én gang i døgnet, eller det ugentlige totaldownload. Hvilken metode du vælger at benytte til at vedligeholde dit kopiregister, kommer an på hvor hurtigt du som anvender har behov for at behandle den nye data.

Bemærk: Hændelser er det eneste måde hvor du som anvender eksplicit kan finde data der er blevet slettet, grundet at Datafordeleren ikke udstiller slettet data.

Hentning af totaldownloads er beskrevet i Eksempel på oprettelse samt vedligeholdelse af kopiregister for fildownload.






Forudsætninger og afgrænsninger

Følgende forudsætninger og afgrænsninger gælder for at kunne følge guiden:

  • Denne guide antager at du som anvender har grundlæggende kendskab til hændelser, som kan findes under Entitetsbaserede hændelser. Her findes generel information om hændelser, brugsscenarier, samt beskrivelse af de data der er udstillet, hvad de betyder og hvordan de kan benyttes.
  • Guiden omhandler kun hvordan tekniske hændelser kan hentes af anvendere. Med tekniske hændelser, menes der hændelser vedrørende opdateringer af registerdata. Denne guide indebærer ikke forretningshændelser, defineret ud fra registrenes egen forretningslogik.
  • Du skal have oprettet en bruger på Datafordeler Administrationen. Se vejledning til dette på Brugeroprettelse Datafordeler Administration.
  • Guiden forudsætter at et kopiregister allerede er oprettet, der afsnittet ”Etablering af kopiregister” i Eksempel på oprettelse samt vedligeholdelse af kopiregister for fildownload kan tages som udgangspunkt. 






Sådan abonnerer du på hændelser


Ligesom entitetsbaserede GraphQL-tjenester, tilgås hændelser via et GraphQL-API. Hændelser tilgås på registerbasis og kræver at du benytter Datafordelerens autentifikation, det vil sige en OAuth hvis der er tale om et register med beskyttede registerdata og API-key til registre med ikke-beskyttede registerdata.

Opsætning med API-key er nærmere beskrevet API-Key, og opsætning med OAuth er nærmere beskrevet under Autentifikation og autorisation for GraphQL-tjenester.

Derudover bruger Datafordeleren i visse tilfælde en IP-allowlist til at verificere om klienten (dit eget IT-system) er autoriseret til at hente det efterspurgte data.

Når dit IT-system sender en forespørgsel til GraphQL-tjenesten med gyldig authentificering og adgang, returneres en stream som IT-systemet kan lytte på.

Efter 10 minutter bliver forbindelsen termineret, men en nye kan oprettes med det samme for at i praksis have en konstant forbindelse.






Eksempler på brug af tjenesten


Abonnering på hændelser ligner kald til de entitetsbaserede GraphQL-tjenester, dog med den forskel at forespørgsler der indsendes med et subscription præfix i stedet for query, og at der ikke er nogen paging grundet at en hændelse bliver returneret ad gangen.

Nedenstående eksempel kalder hændelser for BBR og efterspørger alle de tilgængelige kolonner for hændelsesdata.


subscription {
    BBR_Events {
        eventid
        entityname
        eventaction
        fromfailedimport
        datafordelerRegisterImportSequenceNumber
        datafordelerOpdateringstid
        object_id
        object_datafordelerRowId
        object_datafordelerRowVersion
        object_status
        object_registreringfra
        object_registreringtil
        object_virkningfra
        object_virkningtil
    }
}




Hændelser er udstillet på de samme URL’er som de entitetsbaserede tjenester, derfor kan oprettelse af abonnering på et register, i dette eksempel BBR, kaldes på følgende URL med en API-key som autentificering:

https://graphql.datafordeler.dk/BBR/v1?apiKey=xxxx






Opsætning med Nitro til abonnering på hændelser


I dette eksempel er det valgt at bruge Nitro fra ChiliCream, da det har vist sig effektiv til at teste modtagelse af hændelser via SSE på GraphQL endepunkter. Andre værktøjer kan anvendes, men visse værktøjer som Postman har vist sig ikke at fungere optimalt til at modtage hændelser over SSE (Server Sent Events).

Denne metode giver mulighed for hurtigt at danne overblik over hvordan hændelser fungerer og hvilke data de indeholder, uden at skulle kode noget selv. Dette skal betragtes som en introduktion til hændelser.

For bedste resultater anvendes et register som hyppigt indlæser pakker, f.eks. BBR. Eksempel på opsætning af Connection Settings til BBR i Nitro:



Herefter kan der laves forespørgsler til BBR, med eksemplet fra forrige sektion, samt URL’et BBR’s endepunkt for entitetsbaserede tjenester.






Projektsetup


Dette afsnit gennemgår den tekniske opsætning af et udviklingsprojekt, der kan abonnere på og håndtere hændelser fra Datafordeleren. Afsnittet viser hvordan abonnementet, der demonstreres ovenfor, kan implementeres i en klient. Eksemplet tager udgangspunkt i et C# Console Application, men principperne kan overføres til andre programmeringssprog og projekttyper.


For at følge eksemplet skal følgende være installeret:

  • .NET 8.0
  • Visual Studio, Visual Studio Code eller lignende IDE

Adgang til NuGet Package Manager






NuGet pakker


Følgende Microsoft NuGet pakker, som er Microsofts officielle biblioteker til konfigurationshåndtering, skal tilføjes til projektet. Disse pakker medfølger ikke automatisk ved opsætning af et nyt Console App projekt og skal installeres ved hjælp af NuGet Package Manager Console:

  • Install-Package Microsoft.Extensions.Configuration.Json
  • Install-Package Microsoft.Extensions.Configuration.FileExtensions






Appsettings


Opret en appsettings.json fil som indeholder Client ID og Client Secret, der fås ved at følge afsnittet om Shared Secrets under Autentificeringsmetoder på Datafordeler Administration.




Et eksempel kan være dette:




Sørg for appsettings-filen er med i build ved at tilføje følgende til .csproj:




Filen er i eksemplet placeret følgende sted:






Adgang til Datafordelerens API


For at kunne tilgå Datafordelerens API, skal der hentes en access token. Først oprettes der en metode til at hente access token ud fra Client ID og Client Secret.

Denne kontakter https://auth.datafordeler.dk/realms/distribution/protocol/openid-connect/token som er endpointet der bruges til at hente access token.

Her er der sat op således at der bruges en ConfigurationBuilder til at hente fra appsettings.json, hvorefter ens access token returneres, og derefter kan bruges til at gennemføre opfølgende kald.

Bemærk at følgende blot er et eksempel på hvordan det kan implementeres.








Abonnement på hændelser


Efter at have hentet en access token som beskrevet forrige afsnit, kan man nu bruge denne til at abonnere på hændelser for et givent register. I dette eksempel bruges BBR. Forespørgslen som sendes afsted i variablen ”GraphQlQuery” og URL’et vil være de samme værdier som bruges under Eksempler pa brug af tjenesten.

Ved kald til BBR endepunktet med subscription forespørgslen, returneres en stream som lytter efter nye hændelser for registeret. Kommer der nye hændelser, vil disse blive tilføjet til en tæller og printet i konsollen. Til sidst printes det totale antal hændelser til konsollen.

I praksis ville man typisk processere dataen i hændelserne man modtager, afhængigt af hvilken funktion ens IT-system har. F.eks. ville man lave yderligere kald til BBR registeret for at få de data som hændelserne berør, eller processere hændelserne til at opdatere sin database.

Dette er blot et eksempel på hvordan en klient der abonnerer på hændelser kan implementeres. Hvad der sker med hændelserne bagefter, kommer meget an på hvad anvender IT-systemets funktion er.

Vedligeholdelse af kopiregister med hændelser kommer med et eksempel på dette.













Hændelsesdata


Når en hændelse modtages fra et register, i dette eksempel BBR, vil indholdet ligne nedenstående. En forklaring på hvad felterne betyder findes på Entitetsbaserede hændelser på Datafordeleren.

Disse data kan bruges til at lave en ny query, der henter objektet fra hændelsen via registerets GraphQL-tjeneste.


{
    "data": {
        "BBR_Events": {
            "datafordelerOpdateringstid":"2025-06-24T13:46:02.424335Z",
            "datafordelerRegisterImportSequenceNumber":99999999,
            "entityname":"Bygning",
            "eventaction":"i",
            "eventid":1177475,
            "object_datafordelerRowId":"3b1040ef-ca52-4cb4-9788-909102a44155",
            "object_datafordelerRowVersion":1,
            "object_id":"49b2aafe-5fb4-42b5-b22d-7104a616804f",
            "object_registreringfra":"2025-06-24T13:46:02.424335Z",
            "object_registreringtil":"2025-06-24T13:46:02.424335Z",
            "object_status":"6",
            "object_virkningfra":"2025-06-24T13:46:02.424335Z",
            "object_virkningtil":"2025-06-24T13:46:02.424335Z"
        }
    }
}






Vedligeholdelse af kopiregister med hændelser


Når dit system modtager hændelser som vist i Abonnement på Hændelser, indeholder disse kun metadata om ændringerne - ikke de faktiske registerdata. For at vedligeholde dit kopiregister kan du implementere opfølgende queries, der henter de komplette data for de objekter som hændelserne refererer til.

Dette kapitel viser hvordan du kan udvide kodeeksemplet fra Abonnement på Hændelser til at generere og udføre GraphQL-queries baseret på de modtagne hændelser.






Opfølgende queries på hændelser


For at holde den totaldownloadede entitet opdateret, skal der laves opfølgende kald på de hændelser der modtages. Her tages der udgangspunkt i hændelse der gives som eksempel fra Hændelsesdata. Dens data kan bruges til at fremsøge den specifikke række via. BBR’s GraphQL-tjeneste, ved at bruge feltet object_datafordelerRowId, som svarer til det tilsvarenede felt datafordelerRowId, der udstilles på GraphQL entiteten BBR_Bygning, hvilket ses på entitiyname.

Nedenstående query kan f.eks. bruges som opfølgende query mod BBR’s GraphQL-tjeneste. Udover at filtrere på datafordelerRowId bruges datafordelerRowVersion, som også findes i metadataen på en hændelse, for at være sikker på det er den korrekte version af dataen der sendes en forespørgsel på.

Har man behov for at finde data for flere hændelser i samme kald, kan man med fordel batche dem i et kald med en IN operator på datafordelerRowId.

Bemærk

Grundet at CPR udstilles gennem Custom tjenester, så er det denne der skal laves en forespørgsel mod, og ikke nogen speciel entitet.

Hændelser for CPR uddybes under Entitetsbaserede hændelser


query {
    BBR_Bygning(
        where: {
            and: [
                { datafordelerRowId: { eq: "3b1040ef-ca52-4cb4-9788-909102a44155" } }
                { datafordelerRowVersion: { eq: 2 } }
            ]
        }
    ) {
        pageInfo {
            endCursor
            hasNextPage
        }
        nodes {
            husnummer
            id_lokalId
            registreringFra
            registreringTil
            status
            virkningFra
            virkningTil
            datafordelerRowId
            datafordelerRowVersion
        }
    }
}




Processering af hændelser


Anvender IT-systemet fra Abonnement på hændelser kan omskrives til at håndtere events og generere den opfølgende query fra Opfølgende queries på hændelser.

Alternativt udstilles datafordelerRegisterImportSequenceNumber, datafordelerRowId og datafordelerRowVersion også med fildownloads, se Fildownload på Datafordeleren. Dette gør det muligt at direkte mappe hændelser til dit kopiregister data, når hændelser processeres, beroende på hvad anvender IT-systemets funktion er.













Alternativ til abonnering


Hvis man vil hente data mere sjældent, kan GraphQL queries benyttes i stedet for at abonnere på hændelser. Se Entitetsbaserede hændelser for mere information for GraphQL queries for hændelser. EventID for hændelser kan bruges for at filtrere på nye hændelser, hvilket giver dette flow:





Med denne opsætning er det op til anvenderen at bestemme hvornår nye hændelser skal hentes og processeres. Bemærk at queries for hændelser, i modsætning til abonnering, har paginering og returnerer flere hændelser. Queries tillader også anvender at hente historiske hændelser. En query for nye BBR-hændelser, der det sidste kendte Event ID er 36, kan f.eks. være:


query {
    BBR_Events(where: { eventid: { gt: 36 } }) {
        nodes {
            object_datafordelerRowId
            entityname
            eventaction
            eventid
        }
    }
}




Resterende proces er ens med den for abonnering, der er beskrevet i dette dokument. F.eks. kan en opfølgende query for den relevante entitet laves med de object_datafordelerRowId der er returneret for at hente den nye data. 






Opsummering


Efter at have fulgt trinene i denne guide, har du nu implementeret en komplet løsning til at abonnere på og håndtere hændelser fra Datafordeleren. Din implementering omfatter følgende funktionalitet i rækkefølge:

  1. Projektstruktur: Dit C#-projekt er korrekt opsat med nødvendige NuGet-pakker (Microsoft.Extensions.Configuration, Npgsql) og konfigurationsfiler (appsettings.json).
  2. Autentificering: Du har implementeret programmatisk hentning af access tokens til sikker kommunikation med Datafordelerens API'er.
  3. Hændelsesabonnement: Din applikation kan nu abonnere på tekniske hændelser for specifikke registre (f.eks. BBR) via GraphQL subscriptions og modtage nær realtidsdata.
  4. Hændelsesbehandling: Systemet lytter aktivt på nye hændelser og kan deserialisere modtagne hændelsesdata med information om entitetsnavne, handlingstyper og objektidentifikatorer.
  5. Opfølgende queries: Du har implementeret funktionalitet til at generere og udføre opfølgende GraphQL-queries baseret på hændelsesdata.
  6. Kopiregister-vedligeholdelse: Din løsning kan nu vedligeholde et lokalt kopiregister i realtid ved at kombinere totaldownloads med hændelsesbaserede opdateringer.