Datahub RLP
Der Node fragt einen Datenendpunkt des Datahub Rheinland-Pfalz über die dataCycle API v4 mit einem Zugriffs-Token ab, sammelt alle Ergebnisseiten, löst ausgewählte Verknüpfungen (JSON-LD) auf und gibt jeden Inhalt als flaches Objekt in Punktnotation aus. Er eignet sich für touristische Points of Interest, Veranstaltungen, Touren und Unterkünfte, die anschließend in ein Smart Data Model überführt werden.
- Node-Typ
- datahub-rlp
- Paket
- @htag/node-red-contrib-hypertegrity-pointofinterest
- Eingänge / Ausgänge
- 1 / 1
- Datenquelle
- Datahub Rheinland-Pfalz (dataCycle API v4)
Wofür Sie den Node verwenden
Der Datahub Rheinland-Pfalz ist die touristische Datenplattform des Landes und läuft auf der Software dataCycle. Inhalte wie Sehenswürdigkeiten, Veranstaltungen, Wanderwege oder Gastronomiebetriebe werden dort als JSON-LD mit vielen Verknüpfungen gepflegt: Ein Ort verweist auf Bilder, Adressen, Öffnungszeiten und Klassifikationen, eine Veranstaltung auf ihren Veranstaltungsort und ihre Serie. Der Datahub-RLP-Node übernimmt den Abruf mitsamt Seitenwechsel (Pagination), Wiederholungen bei Fehlern und der Auflösung dieser Verknüpfungen und liefert eine Struktur, die sich ohne tiefes JSON-LD-Wissen weiterverarbeiten lässt.
Typische Einsatzfälle sind:
- Touristische Points of Interest einer Region als
PointOfInterest-Entitäten in einen NGSI-LD Context Broker übernehmen. - Veranstaltungskalender regelmäßig abrufen und inkrementell nach Änderungsdatum nachladen.
- Datenintegration mehrerer Datenendpunkte (gespeicherte Suchen oder Inhaltssammlungen) in eine urbane Datenplattform.
So funktioniert der Node
Auslösen
Eine eingehende Nachricht startet den Abruf. Optional überschreibt sie Endpunkt, Sprache oder Filter.
Seiten abrufen
Der Node sendet POST-Anfragen an /api/v4/endpoints/<ID> und folgt meta.total und meta.pages, bis alle Seiten (oder das Seitenlimit) erreicht sind. Bei Drosselung wartet er und wiederholt.
Auflösen
Verknüpfungen auflösen: Ausgewählte Pfade gehen als include-Parameter mit; verbleibende @id-Referenzen werden aus bereits geladenen Inhalten derselben Abfrage ergänzt.
Umformen
Jeder Inhalt wird in ein flaches Objekt mit Punktnotation überführt, zum Beispiel address.postalCode.
Ausgeben
Alle Inhalte in einer Nachricht oder eine Nachricht je Seite als Sequenz mit msg.parts.
Ergebnis: Ein Array flacher Inhalte plus Metadaten in msg.datahub, bereit für die Abbildung auf ein Smart Data Model.
Der Node ist triggerbasiert und arbeitet keine Zeitpläne selbst ab. Kombinieren Sie ihn mit einem Inject-Node. Laufende Abfragen werden bei einem Deploy oder beim Stoppen von Node-RED abgebrochen, damit eine veraltete Konfiguration nicht weiter Seiten anfordert.
Konfiguration
Der Bearbeitungsdialog hat vier Registerkarten.
Registerkarte „Verbindung“
| Feld | Typ | Standard | Bedeutung |
|---|---|---|---|
| Name | Text | leer | Anzeigename des Nodes im Flow. |
| Basis-URL | Text (Pflicht) | siehe unten | Adresse der dataCycle-Instanz. Muss mit http:// oder https:// beginnen. Auch andere dataCycle-Installationen sind damit erreichbar. |
| Datenendpunkt | Text (Pflicht) | leer | UUID oder Slug der Inhaltssammlung beziehungsweise gespeicherten Suche. Fügen Sie eine komplette API-URL aus der Datahub-Oberfläche ein, wird sie automatisch in Basis-URL, Datenendpunkt und (falls enthalten) Token aufgeteilt. |
| Sprache | Text | de | Angeforderte Inhaltssprache, mehrere kommagetrennt (zum Beispiel de,en). |
| Zugriffs-Token | Passwort (Credential) | leer | Token des Datahub-Benutzers. Wird verschlüsselt im Credentials-Store von Node-RED gespeichert, im Anfragekörper als token übertragen und zusätzlich als Authorization: Bearer-Header gesendet. |
| Verbindung testen & Attribute laden | Button mit Auswahl „Suchtiefe“ (1 bis 5, Standard 2) | – | Fragt eine Stichprobe von fünf Inhalten ab, zeigt Titel der Sammlung, Anzahl der Inhalte und Seiten an und ermittelt kaskadierend bis zur gewählten Suchtiefe alle verknüpfbaren Attribute. Das Ergebnis erscheint auf der Registerkarte „Verknüpfungen“. |
Standardwerte der URL-Felder:
Basis-URL: https://data.rlp-tourismus.de
Registerkarte „Verknüpfungen“
| Feld | Typ | Standard | Bedeutung |
|---|---|---|---|
Verknüpfte Inhalte auflösen (includes) | Auswahlbaum mit Kontrollkästchen | leer | Attribute, deren verknüpfte Inhalte vollständig abgerufen werden sollen. Ausgewählte Pfade gehen als API-Parameter include mit; übergeordnete Pfade werden automatisch ergänzt (image zu image.author). Mit ⚠ markierte Pfade verweisen auf denselben Inhaltstyp zurück und vervielfachen die Datenmenge. |
| Alle auswählen / Auswahl aufheben | Buttons | – | Wählt alle ermittelten Attribute außer den rekursiven aus beziehungsweise leert die Auswahl. |
| Pfad hinzufügen | Text mit Button | leer | Ergänzt einen Pfad manuell, zum Beispiel image.author, falls er in der Stichprobe nicht vorkam. Erlaubt sind Buchstaben, Ziffern, _, :, - und Punkte als Trenner. |
Registerkarte „Abfrage“
| Feld | Typ | Standard | Bedeutung |
|---|---|---|---|
| Seitengröße | Zahl (1 bis 500) | 20 | Anzahl der Inhalte je API-Anfrage (page[size]). |
| Seitenlimit | Zahl | 0 | 0 ruft alle Seiten ab. Jeder andere Wert begrenzt die Zahl der angefragten Seiten. Unabhängig davon gilt eine feste Obergrenze von 2000 Seiten je Lauf. |
| Anfrage-Pause | Zahl in Millisekunden | 500 | Pause zwischen zwei Seitenabfragen gegen das Rate-Limit des Datahub. |
| Sortierung | Text | leer | API-Parameter sort, zum Beispiel dct:created, dct:modified, name oder default. Ein vorangestelltes Minuszeichen kehrt die Richtung um. |
| Felder | Text | leer | API-Parameter fields: schränkt die ausgelieferten Attribute ein. Das ist der wirksamste Hebel gegen große Datenmengen. |
| Zusätzlicher Filter | JSON-Textfeld | leer | JSON für den API-Parameter filter, der zusätzlich zu den im Datenendpunkt hinterlegten Filtern gilt. Ungültiges JSON wird beim Speichern mit einer Warnung und zur Laufzeit mit einem Fehler quittiert. |
Registerkarte „Ausgabe“
| Feld | Typ | Standard | Bedeutung |
|---|---|---|---|
| Ausgabe | Auswahl | „Alle Seiten in einer Nachricht“ | collected: der Node sammelt alle Seiten und sendet eine Nachricht. perPage: je Seite eine Nachricht als Sequenz mit msg.parts; es liegt immer nur eine Seite im Speicher. |
| Trennzeichen | Text | . | Zeichen zwischen den Pfadsegmenten der flachen Schlüssel. |
| Max. Tiefe | Zahl (1 bis 20) | 8 | Verschachtelungstiefe, ab der nur noch die Referenz (@id) übernommen wird. |
| Arrays vereinfachen | Kontrollkästchen | aktiv | Erzeugt address.postalCode statt address.0.postalCode, wenn ein Array genau einen Eintrag hat. |
| Referenzen auflösen | Kontrollkästchen | aktiv | Ergänzt verbleibende @id-Referenzen aus Inhalten, die in derselben Abfrage bereits vollständig geliefert wurden. Im Modus „pro Seite“ wirkt das nur innerhalb einer Seite. |
| Max. Schlüssel/Inhalt | Zahl | 5000 | Sicherheitsnetz: Überschreitet ein Inhalt beim Abflachen diese Zahl an Schlüsseln, wird er gekürzt und eine Warnung ausgegeben. 0 hebt die Grenze auf. |
Eingang
Jede Nachricht löst den Abruf aus. Drei Eigenschaften können die Konfiguration für diese eine Nachricht überschreiben.
| Eigenschaft | Typ | Bedeutung |
|---|---|---|
msg.payload | beliebig | Löst den Abruf aus. Der Inhalt wird nicht ausgewertet. |
msg.endpointId | Text | Überschreibt den konfigurierten Datenendpunkt (UUID oder Slug). |
msg.language | Text | Überschreibt die konfigurierte Sprache. |
msg.filter | Objekt | Wird mit dem konfigurierten zusätzlichen Filter zusammengeführt; gleichnamige Schlüssel aus der Nachricht gewinnen. Eignet sich für inkrementelle Abrufe, zum Beispiel {"attribute": {"dct:modified": {"in": {"min": "2026-09-01"}}}}. |
Ausgang
msg.payload ist ein Array flacher Objekte, ein Objekt je Inhalt. Verschachtelte und verknüpfte Daten erscheinen in Punktnotation. msg.topic enthält den Titel der Inhaltssammlung (aus meta.collection.name), ersatzweise die Endpunkt-ID.
[
{
"@id": "3f2a9c1e-5b7d-4e8a-9c2f-1d4b6e8a0c3f",
"@type.0": "dcls:POI",
"@type.1": "Place",
"name": "Burgruine Beispielstein",
"description": "Ruine einer Höhenburg aus dem 12. Jahrhundert.",
"dct:modified": "2026-09-28T10:12:00.000+02:00",
"address.streetAddress": "Burgweg 1",
"address.postalCode": "67655",
"address.addressLocality": "Beispielstadt",
"geo.latitude": 49.4447,
"geo.longitude": 7.7689,
"image.contentUrl": "https://data.rlp-tourismus.de/images/example.jpg",
"dc:classification.name": "Burg"
}
]
| Feld | Bedeutung |
|---|---|
@id, @type.n | JSON-LD-Kennung und Typen des Inhalts. Ein @type-Array mit mehreren Einträgen erhält Indizes; @context wird nicht übernommen. |
name, description, dct:modified, … | Attribute des Inhalts, wie von der API geliefert. Welche Attribute vorhanden sind, hängt vom Inhaltstyp und von „Felder“ ab. |
address.postalCode, geo.latitude, … | Abgeflachte verschachtelte Objekte. Bei Arrays mit mehr als einem Eintrag erscheint der Index, zum Beispiel image.0.contentUrl. |
….@id | Referenz auf einen verknüpften Inhalt, der nicht aufgelöst wurde oder jenseits von „Max. Tiefe“ liegt. |
Zusätzlich setzt der Node folgende Nachrichteneigenschaften:
| Eigenschaft | Bedeutung |
|---|---|
msg.datahub | Metadaten der Abfrage: baseUrl, endpointId, collection, language, include, total, pages, pagesFetched (nur gesammelt) beziehungsweise pageNumber (nur pro Seite), pageSize, itemCount, resolvedReferences, truncatedItems, truncated (nur gesammelt) und outputMode. |
msg.parts | Nur im Modus „pro Seite“: id, index (ab 0), count (geplante Seiten, 0 wenn unbekannt), type: "array" und len (Seitengröße), damit ein Join-Node die Seiten zu einem flachen Array zusammenführt. |
msg.complete | Nur im Modus „pro Seite“ auf der letzten Nachricht: true. |
Beispiel-Flow
Das Paket bringt einen Beispiel-Flow mit. Sie importieren ihn in Node-RED über Menü → Importieren → Beispiele → @htag/node-red-contrib-hypertegrity-pointofinterest → datahub-rlp. Alternativ laden Sie die Datei datahub-rlp.json herunter und importieren sie über Menü → Importieren. Das Token tragen Sie nach dem Import selbst ein.
Inject
Ein Inject-Node löst den Abruf manuell oder in einem festen Intervall aus.
Datahub RLP
Der Node ruft einen Datenendpunkt mit Seitengröße 50 und Seitenlimit 1 ab, löst Bilder, Orte, Adressen und Klassifikationen auf und gibt je Seite eine Nachricht aus.
Debug
Ein Debug-Node zeigt die flachen Inhalte in der Seitenleiste an.
Beispiel-Flow als JSON anzeigen
[
{"id": "tab1", "type": "tab", "label": "Datahub RLP", "disabled": false, "info": ""},
{"id": "inject1", "type": "inject", "z": "tab1", "name": "", "props": [{"p": "payload"}], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 120, "y": 140, "wires": [["datahub1"]]},
{"id": "datahub1", "type": "datahub-rlp", "z": "tab1", "name": "", "baseUrl": "https://data.rlp-tourismus.de", "endpointId": "<ENDPUNKT-UUID>", "language": "de", "pageSize": "50", "maxPages": "1", "requestDelay": 500, "outputMode": "perPage", "includes": "[\"image\",\"location\",\"location.address\",\"location.geo\",\"dc:classification\"]", "fields": "", "sort": "", "filterJson": "", "separator": ".", "collapseSingleArrays": true, "maxFlattenDepth": "10", "maxKeysPerItem": "10000", "resolveKnownLinks": true, "x": 300, "y": 140, "wires": [["debug1"]]},
{"id": "debug1", "type": "debug", "z": "tab1", "name": "Datahub-RLP data", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "x": 510, "y": 140, "wires": []}
]
Status und Fehler
| Anzeige | Bedeutung |
|---|---|
| Blauer Punkt „page 1...“ beziehungsweise „3/12 - page 3...“ | Die genannte Seite wird abgerufen; bei bekannter Seitenzahl mit Fortschritt. Ein Zusatz „(try 2/5)“ zeigt eine Wiederholung. |
| Gelber Ring „rate limited - waiting 12s (try 2/8)“ | Der Datahub hat mit HTTP 429 oder 503 geantwortet. Der Node wartet entsprechend Retry-After oder mit exponentiell wachsender Pause (1,5 s, 3 s, 6 s, … bis 60 s) und versucht es bis zu achtmal. |
| Blauer Punkt „resolving & flattening...“ | Referenzen werden aufgelöst und die Inhalte abgeflacht (Modus „gesammelt“). |
| Blauer Punkt „sent page 2/12 (100 contents)“ | Eine Seite wurde gesendet (Modus „pro Seite“). |
| Grüner Punkt „240 contents (12 pages)“ oder „240 contents in 12 messages“ | Der Lauf ist abgeschlossen. |
| Roter Ring „invalid filter“ | Der konfigurierte zusätzliche Filter ist kein gültiges JSON. |
| Roter Ring „invalid config“ | Basis-URL, Datenendpunkt, Token oder Seitengröße fehlen beziehungsweise sind ungültig, zum Beispiel „No access token configured.“. |
| Roter Ring „failed“ | Der Abruf ist endgültig gescheitert. Typische Meldungen: „Datahub request failed - HTTP 401: Access token invalid or not authorized for this data endpoint“, „HTTP 404: Data endpoint id/slug unknown“ oder „Datahub request for page 3 failed after 8 attempts. … The Datahub is throttling this token …“. |
| Warnung „Datahub page 3 attempt 1/5 failed: … - retrying in 2s“ | Ein vorübergehender Fehler (Timeout nach 60 Sekunden, Netzwerkfehler, HTTP 5xx); der Node wiederholt bis zu fünfmal. |
| Warnung „Page limit reached - only 50 of 240 contents were fetched.“ | Das Seitenlimit hat den Abruf beendet, bevor alle Inhalte geladen waren. |
| Warnung „2 content(s) exceeded the limit of 5000 keys and were truncated. …“ | Das Sicherheitsnetz hat zugeschlagen; wählen Sie weniger oder keine rekursiven Verknüpfungen oder schränken Sie „Felder“ ein. |
HTTP 400, 401, 403, 404 und 422 führen ohne Wiederholung zum Abbruch. Fehler werden über done(error) gemeldet und können mit einem Catch-Node abgefangen werden. Wird ein Lauf durch einen Deploy abgebrochen, endet er ohne Fehler und ohne Ausgabe.
Hinweise
- Rate-Limit: Der Datahub drosselt die Anzahl der Anfragen je Token und antwortet dann mit HTTP 429. Entscheidend ist die Zahl der Anfragen, nicht die Größe der Sammlung. Wirksame Gegenmaßnahmen: größere Seiten, eine Anfrage-Pause, ein Seitenlimit, nur die wirklich benötigten Verknüpfungen, eine Einschränkung über „Felder“ und inkrementelle Läufe über
filter[attribute][dct:modified]. - Rekursive Verknüpfungen: Pfade wie
superEvent.subEventführen von einer Veranstaltung zu ihrer Serie und zurück zu allen Geschwister-Veranstaltungen. Ein einzelner Inhalt kann dadurch auf Hunderttausende Schlüssel anwachsen. Die Attribut-Erkennung markiert solche Pfade und nimmt sie von „Alle auswählen“ aus. - Speicherbedarf: Bei großen Sammlungen empfiehlt sich die Ausgabe „pro Seite“, gegebenenfalls gefolgt von einem Join-Node oder einer Verarbeitung je Seite.
- Smart Data Model: Der Node überführt die Inhalte bewusst nicht selbst in ein Smart Data Model. Die Abbildung auf
PointOfInterest,Eventoder andere Modelle übernimmt der nachgelagerte NGSI-LD Builder. - Personenbezogene Daten: Aufgelöste Verknüpfungen können personenbezogene Daten enthalten, zum Beispiel
author,publisheroder Kontaktangaben alsPersonmit Name, E-Mail-Adresse oder Telefonnummer. Prüfen Sie im Flow, welche dieser Attribute weiterverarbeitet oder veröffentlicht werden dürfen, und beachten Sie die Nutzungsbedingungen des Datahub Rheinland-Pfalz. - Zugangsdaten: Das Token wird verschlüsselt gespeichert und ist in exportierten Flows nicht enthalten. Beim Verbindungstest wird ein neu eingetipptes Token übertragen; andernfalls nutzt der Editor das gespeicherte Token.