Datensatzserie fortführen per API¶
Für regelmäßig erscheinende Daten – etwa einen neuen Monatsstand – wird die CSV-Datei nicht ersetzt, sondern als neuer Eintrag an eine Datensatzserie angehängt. Existiert die mit dataSeriesId angegebene Serie bereits, erweitert das Backend sie um den neuen Eintrag; besteht sie noch nicht, legt es sie beim ersten Aufruf an.
Was ist eine Datensatzserie?¶
Eine Datensatzserie ist eine logische Gruppierung von Datensätzen, die regelmäßig oder kontinuierlich aktualisiert werden –
z. B. monatliche Verkehrszählungen oder jährliche Schulstatistiken.
In den Metadatenstandards DCAT-AP (Europa) und DCAT-AP.de (Deutschland) wird dieses Konzept als dcat:DatasetSeries beschrieben.
Alle Einträge der Serie teilen dieselben Metadaten (Katalog, Lizenz, Herausgeber, Kategorien).
Jeder neue Eintrag referenziert über previousDatasetId den unmittelbar vorherigen Datensatz in der Serie –
dadurch entsteht eine nachvollziehbare chronologische Kette.
Voraussetzungen¶
- Client-ID und Client-Secret des Service Accounts liegen vor
- CSV-Datei ist lokal vorhanden, Encoding und Delimiter sind bekannt
- Datensatz-ID des zuletzt veröffentlichten Datensatzes der Serie ist bekannt
- Optional: neue Schema-Version des Schemas ist bekannt (siehe Schema-Repository)
Vorgehen¶
1. Token abrufen¶
Für den Request wird ein gültiges JWT-Token benötigt – siehe API-Token abrufen.
2. Datensatzserie fortführen¶
Das Fortführen setzt einen bereits vorhandenen Datensatz voraus, der über die API hochgeladen wurde (siehe Datensatz hochladen per API).
Umgebungen (Produktion/Test)
Die Beispiel-Requests stehen jeweils in einer Produktions- und einer Test-Variante bereit, umschaltbar über die Tabs.
Endpunkt¶
POST https://staging-backend.odi.schleswig-holstein.de/upload/csv/append
POST https://staging-backend.odi-stage.schleswig-holstein.de/upload/csv/append
Felder¶
| Feld | Pflicht | Typ | Beschreibung |
|---|---|---|---|
previousDatasetId |
Pflicht | string | ID des zuletzt veröffentlichten Datensatzes der Serie |
datasetId |
Pflicht | string | Frei wählbare ID des neuen Datensatzes |
startDate |
Pflicht | string | Startdatum des neuen Zeitraums (ISO 8601, z. B. 2024-02-01) |
endDate |
Optional | string | Enddatum des neuen Zeitraums (ISO 8601) |
schemaVersion |
Optional | string | Version des Schemas (z. B. 1.1.1) – ohne Angabe gilt die aktuelle Version des Schemas |
delimiter |
Pflicht | string | Trennzeichen der CSV-Datei (z. B. ; oder ,) |
encoding |
Pflicht | string | Zeichenkodierung (z. B. UTF-8) |
quote |
Optional | string | Anführungszeichen-Zeichen (z. B. ") |
escapeChar |
Optional | string | Escape-Zeichen innerhalb von Feldern in Anführungszeichen (z. B. \) |
file |
Pflicht | binary | Die neue CSV-Datei |
datasetTitle |
Pflicht | string | Titel des neuen Datensatzes |
dataSeriesId |
Pflicht | string | ID der Datensatzserie – existiert sie, wird der neue Datensatz angehängt; sonst wird sie angelegt |
datasetDescription |
Pflicht | string | Beschreibung des neuen Datensatzes |
dataSeriesTitle |
Optional | string | Titel der Serie – wird nur beim Anlegen einer neuen Serie ausgewertet |
dataSeriesDescription |
Optional | string | Beschreibung der Serie – wird nur beim Anlegen einer neuen Serie ausgewertet |
Serienspezifische Felder
dataSeriesId bestimmt, an welche Serie der neue Datensatz angehängt wird, und muss bei jedem Request angegeben werden.
dataSeriesTitle und dataSeriesDescription wertet das Backend nur aus, wenn es die Serie neu anlegt; beim Erweitern einer bestehenden Serie werden sie ignoriert.
Katalog, Lizenz, Herausgeber, Kategorien, Raumbezug und Schema-ID übernimmt der neue Datensatz vom Vorgänger (previousDatasetId).
Empfehlung: datasetId einheitlich benennen
Eine bewährte Konvention ist <thema>-YYYY-MM-DD, z. B. windkraftanlagen-2026-02-01.
So lassen sich Einträge einer Serie chronologisch eindeutig zuordnen.
Beispiel-Request¶
curl --request POST \
--url https://staging-backend.odi.schleswig-holstein.de/upload/csv/append \
--header "Authorization: Bearer <access_token>" \
--header 'content-type: multipart/form-data' \
--form previousDatasetId=windkraftanlagen-2026 \
--form datasetId=windkraftanlagen-2026-02-01 \
--form startDate=2024-02-01 \
--form-string 'delimiter=;' \
--form encoding=UTF-8 \
--form 'quote="' \
--form 'file=@/pfad/zu/windkraftanlagen-2026-02-01.csv;type=text/csv' \
--form 'datasetTitle=Windkraftanlagen 01.02.2026' \
--form datasetDescription=Windkraftanlagen \
--form dataSeriesId=windkraftanlagen-dataseries \
--form dataSeriesTitle=Windkraftanlagen
curl --request POST \
--url https://staging-backend.odi-stage.schleswig-holstein.de/upload/csv/append \
--header "Authorization: Bearer <access_token>" \
--header 'content-type: multipart/form-data' \
--form previousDatasetId=windkraftanlagen-2026 \
--form datasetId=windkraftanlagen-2026-02-01 \
--form startDate=2024-02-01 \
--form-string 'delimiter=;' \
--form encoding=UTF-8 \
--form 'quote="' \
--form 'file=@/pfad/zu/windkraftanlagen-2026-02-01.csv;type=text/csv' \
--form 'datasetTitle=Windkraftanlagen 01.02.2026' \
--form datasetDescription=Windkraftanlagen \
--form dataSeriesId=windkraftanlagen-dataseries \
--form dataSeriesTitle=Windkraftanlagen
curl: Trennzeichen und Dateityp
Zwei Angaben im Beispiel-Request sind nötig, damit curl die Felder richtig überträgt:
--form-string 'delimiter=;'statt--form: Bei--formwertet curl ein Semikolon als Trennzeichen für eigene Optionen aus und sendet das Feld leer.;type=text/csvhinter dem Dateipfad: Ohne diese Angabe sendet curl die Datei alsapplication/octet-stream, und das Backend lehnt sie mit HTTP 400 ab.
Beispiel-Response (Erfolg)¶
{
"datasetId": "windkraftanlagen-2026-02-01",
"dataSeriesUrl": "https://opendata.schleswig-holstein.de/collection/windkraftanlagen-dataseries",
"datasetUrl": "https://opendata.schleswig-holstein.de/dataset/windkraftanlagen-2026-02-01"
}
Beispiel-Response (Fehlerfall – Validierung fehlgeschlagen)¶
{
"status": "error",
"type": "invalid file",
"message": "Validation of Csv-File was not valid!",
"context": "CsvUploadService",
"errors": [
{
"description": "The cell \"Harburg\" in row at position \"2\" and field \"KREIS\" at position \"1\" does not conform to a constraint: constraint \"enum\" is \"['Dithmarschen', 'Kiel', 'Lübeck', ...]\"",
"index": 2,
"field": "KREIS"
}
]
}
Im Fehlerfall wird ein Validierungsbericht im frictionless-Report-Format zurückgeliefert.
Fehlercodes¶
| HTTP-Status | Bedeutung | Mögliche Ursache / Lösung |
|---|---|---|
| 400 | Ungültige Anfrage | Pflichtfeld fehlt, falsches Format oder CSV entspricht nicht dem Schema |
| 401 | Nicht authentifiziert | Access-Token fehlt oder ist abgelaufen → neuen Token abrufen. Oder dem Service Account ist kein gültiger ckan-token zugeordnet → Zugriff prüfen |
| 403 | Keine Berechtigung | Das CKAN-Konto hinter dem ckan-token hat im Datenkatalog keine Schreibrechte für den Herausgeber |
| 413 | Datei zu groß | Datei übersteigt das serverseitige Größenlimit von 300 MB |
| 500 | Interner Serverfehler | Kontakt zum ODI-Support aufnehmen |
Nächste Schritte¶
Ein Datensatz in einer Datensatzserie kann bei Bedarf aktualisiert werden.
- Datensatz aktualisieren per API – eine bestehende CSV-Datei ersetzen