Datensatz hochladen per API

Dieser Guide beschreibt, wie eine CSV-Datei samt Metadaten über die ODI-API hochgeladen wird. Der Ablauf gliedert sich in drei Phasen: Schema-ID ermitteln → Metadaten-IDs ermitteln → Token abrufen → CSV hochladen. Datei und Metadaten werden dabei in einem einzigen HTTP-Multipart-Request übergeben.

Das Backend validiert die hochgeladene CSV-Datei automatisch gegen das angegebene Schema. Nur bei erfolgreicher Validierung wird der Datensatz angelegt.

Test-System verfügbar

Für die Entwicklung und Tests steht ein Staging-System bereit. Die Zugangsdaten (Keycloak-URL, Realm, Client-Credentials) sind auf Anfrage erhältlich. Bitte wende dich dazu an das ODI-Team.

Voraussetzungen

  • Client-ID und Client-Secret eines Keycloak Service Accounts liegen vor (Admins: siehe Programmatischen API-Zugriff einrichten)
  • CSV-Datei ist lokal vorhanden, Encoding und Delimiter sind bekannt
  • Schema-ID und Schema-Version des passenden Schemas sind bekannt (siehe Schema-ID ermitteln)
  • Folgende Metadaten-IDs sind bekannt (siehe Metadaten-IDs abrufen):
    • Katalog-Name (catalogue), z. B. opendata-sh
    • Lizenz-ID (licenseId), z. B. http://dcat-ap.de/def/licenses/cc-zero
    • Publisher-ID (publisherId), z. B. dataport
    • Kategorie-IDs (categoryIdsJsonString), z. B. ["envi"]
    • Raumbezug-ID (spatialReferenceId), z. B. http://dcat-ap.de/def/politicalGeocoding/stateKey/01

Schema-ID ermitteln

Das Schema definiert die erwartete Struktur der hochzuladenden CSV-Datei. schemaId und schemaVersion sind Pflichtfelder im Upload-Request.

Das Schema-Repository ist unter schema.odi.schleswig-holstein.de/schemas erreichbar. Dort sind alle verfügbaren Schemas mit ihren IDs und Versionen aufgelistet. Die Schema-ID und die Schemaversion befindet sich auf der Schema-Detailseite.

Vorgehen:

  1. Schema-Repository öffnen.
  2. Passendes Schema identifizieren.
  3. Schema-ID (z. B. 8569) und Version (z. B. 1.3.1) notieren.

Tip

Die verfügbaren Schemas können auch über die Schema-Repository API abgerufen werden.

Metadaten-IDs abrufen

Mehrere Pflichtfelder des Upload-Requests referenzieren Objekte, die im Metadaten-Service verwaltet werden. Eine Übersicht aller verfügbaren IDs und Endpunkte ist unter Metadaten-IDs abrufen zu finden.

Häufig verwendete Werte:

Feld Wert Kommentar
catalogue opendata-sh
licenseId http://dcat-ap.de/def/licenses/cc-zero Creative Commons CC Zero
licenseId http://dcat-ap.de/def/licenses/dl-zero-de/2.0 Datenlizenz Deutschland Zero 2.0
licenseId http://dcat-ap.de/def/licenses/officialWork Amtliches Werk
spatialReferenceId http://dcat-ap.de/def/politicalGeocoding/stateKey/01 Bundesland Schleswig-Holstein
categoryIdsJsonString ["envi"] Umwelt
categoryIdsJsonString ["tran"] Verkehr
categoryIdsJsonString ["gove"] Regierung und öffentlicher Sektor

Token abrufen (Keycloak Service Account)

Alle schreibenden API-Requests erfordern ein gültiges JWT-Token für diesen ein Service-Account notwendig ist.

Tip

Der Service-Account wird vom Administrator angelegt. Eine ausführliche Anleitung zur Einrichtung findet sich unter Programmatischen API-Zugriff einrichten.

Die Zugangsdaten bestehen aus einer Client-ID und einem Client-Secret.

Request:

curl -X POST \
  "https://keycloak.odi.schleswig-holstein.de/realms/open-data-infrastruktur/protocol/openid-connect/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=<client-id>" \
  -d "client_secret=<client-secret>"

Beispiel-Response:

{
  "access_token": "eyJ...",
  "expires_in": 300,
  "token_type": "Bearer"
}

Den Wert von access_token im nächsten Schritt als Bearer-Token verwenden. Dies ist nötig um Daten über die API hochzuladen.

Warning

Client-Secrets niemals in Versionsverwaltungssystemen oder Logs speichern. Tokens sind zeitlich begrenzt gültig (expires_in Sekunden); nach Ablauf muss ein neuer Token angefordert werden.

CSV-Datei hochladen

Zum Hochladen einer CSV-Datei genügt ein einziger Request.

Beim Hochladen wird die CSV-Datei automatisch gegen das angegebene Schema validiert. Im Fehlerfall wird ein Validierungsbericht im frictionless-Report-Format zurückgeliefert – ein Beispiel der Fehlerreports befindet sich weiter unten.

Nach dem erfolgreichen Hochladen wird der Datensatz im Datenkatalog angelegt. Dabei werden folgende Dateien automatisch erzeugt:

Enthält das Schema Geo-Informationen, werden zusätzlich angelegt:

  • GeoJSON-Datei
  • GeoParquet-Datei
  • WFS-Service
  • WMS-Service
  • Kartenansicht (Link zum Masterportal)

Request

POST "https://staging-backend.odi.schleswig-holstein.de/upload/csv"

Felder (Request Body)

Feld Pflicht Typ Beschreibung Quelle
catalogue Pflicht string Katalog, in dem der Datensatz gespeichert wird Metadaten-Service /catalogs
title Pflicht JSON-Objekt Titel des Datensatzes (mehrsprachig) frei wählbar
description Pflicht JSON-Objekt Beschreibung (mehrsprachig) frei wählbar
schemaId Pflicht string ID des Schemas im Schema-Repository Schema-Repository
schemaVersion Pflicht string Version des Schemas Schema-Repository
delimiter Pflicht string Trennzeichen der CSV-Datei (z. B. ; oder ,) bekannt aus Datei
encoding Pflicht string Zeichenkodierung (z. B. UTF-8) bekannt aus Datei
quote Pflicht string Anführungszeichen-Zeichen (z. B. ") bekannt aus Datei
file Pflicht binary Die CSV-Datei lokal
startDate Pflicht string Startdatum des Datensatz-Zeitraums im ISO-8601-Format (z. B. 2024-01-01) bekannt
endDate Optional string Enddatum des Datensatz-Zeitraums im ISO-8601-Format (z. B. 2024-12-31)
licenseId Pflicht string ID der Lizenz Metadaten-Service /licenses
datasetId Pflicht string Frei wählbare ID des Datensatzes frei wählbar
publisherId Pflicht string ID des Herausgebers Metadaten-Service /publisher
categoryIdsJsonString Pflicht string (JSON) JSON-Array der Kategorie-IDs als String Metadaten-Service /categories
spatialReferenceId Pflicht string ID des Raumbezugs Metadaten-Service /places
draft Pflicht string "true" = Draft anlegen; "false" = veröffentlichen

Info

title und description sind mehrsprachige JSON-Objekte, z. B.: {"de": "Windkraftanlagen", "en": "Wind turbines"} Sie werden als JSON-String im multipart-Body übergeben.

Beispiel-Request (Windkraftanlagen)

Der access_token wird im Abschnitt Token abrufen ermittelt.

curl --request POST \
  --url https://staging-backend.odi.schleswig-holstein.de/upload/csv \
  --header 'authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...' \ # <access_token> aus dem vorherigen Schritt
  --header 'content-type: multipart/form-data' \
  --form catalogue=opendata-sh \
  --form 'title={"de":"Windkraftanlagen"}' \
  --form 'description={"de":"Dieser Datensatz enthält Daten und Standorte von genehmigungspflichtigen Windkraftanlagen in Schleswig-Holstein."}' \
  --form schemaId=7269 \
  --form schemaVersion=1.2.2 \
  --form 'delimiter=;' \
  --form encoding=UTF-8 \
  --form 'quote="' \
  --form file=@/pfad/zur/windkraftanlagen.csv \
  --form startDate=2026-01-01 \
  --form licenseId=http://dcat-ap.de/def/licenses/cc-zero \
  --form datasetId=windkraftanlagen-2026 \
  --form publisherId=dataport \
  --form 'categoryIdsJsonString=["ener", "envi"]' \
  --form spatialReferenceId=http://dcat-ap.de/def/politicalGeocoding/stateKey/01 \
  --form draft=false

Beispiel-Response (Erfolg)

{
  "datasetId": "windkraftanlagen-2026",
  "datasetUrl": "https://opendata.schleswig-holstein.de/dataset/windkraftanlagen-2026"
}

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', 'Nordfriesland', 'Hzgt.Lauenburg', 'Ostholstein', 'Plön', 'Pinneberg', 'Rendsburg-Eckernförde', 'Segeberg', 'Schleswig-Flensburg', 'Steinburg', 'Stormarn']\"",
      "index": 2,
      "field": "KREIS"
    }
  ]
}

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 Token fehlt oder abgelaufen → neuen Token abrufen
403 Keine Berechtigung Service Account hat nicht die erforderliche Rolle
413 Datei zu groß Datei übersteigt das serverseitige Größenlimit
500 Interner Serverfehler Kontakt zum ODI-Support aufnehmen

Beispiel-Response (403 – Keine Berechtigung): Tritt auf, wenn der Service Account keine Schreibrechte für den angegebenen Publisher hat oder keine Berechtigung für den Upload eingerichtet wurde.

{
  "status": "error",
  "type": "forbidden",
  "message": "CsvUploadService"
}

Als Draft speichern (optional)

Optional: Als Draft speichern

Durch Setzen von draft=true im Upload-Request wird der Datensatz zunächst als Entwurf angelegt und ist öffentlich noch nicht sichtbar. Dies empfiehlt sich, wenn der Datensatz vor der Veröffentlichung noch manuell geprüft werden soll.

Nächste Schritte