Mit QGIS 4.2.0 am 07.09.2026 gemessen: 0 Fehler. README nennt die Server-Anforderungen (service-desc/OpenAPI, Part-5-Schema, OPTIONS Allow, Merge Patch). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
12 KiB
API_Karte_QGISDemo — Beispiel: Karten-API des VLN Managers aus QGIS ansteuern
Dieses Repository zeigt an einem lauffähigen QGIS-Plugin, wie die
Karten-API des VLN Managers (https://api.flurneuordnung-sachsen.de/v2)
aus QGIS bzw. PyQGIS angesteuert wird: Anmeldung, Laden der
Verfahrens-Layer als editierbare QGIS-Layer und Zurückschreiben der
Änderungen. Es liest und schreibt dieselben Daten, die auch das Web-GIS
(karte.flurneuordnung-sachsen.de) verwendet.
Der Code ist bewusst als Referenz-Implementierung gehalten — wer eine eigene Integration (Plugin, Skript, Processing-Werkzeug) bauen will, findet hier alle Bausteine.
Die Ansteuerung in Kürze
So sieht der minimale Ablauf in PyQGIS aus (vollständige, robuste Fassung in vln_karten/api_client.py):
import json
from qgis.PyQt.QtCore import QUrl
from qgis.PyQt.QtNetwork import QNetworkRequest
from qgis.core import QgsBlockingNetworkRequest
BASE = "https://api.flurneuordnung-sachsen.de/v2"
def request(method, path, payload=None, api_key=None):
req = QNetworkRequest(QUrl(BASE + path))
req.setHeader(QNetworkRequest.KnownHeaders.ContentTypeHeader, "application/json")
if api_key:
req.setRawHeader(b"X-API-Key", api_key.encode())
blk = QgsBlockingNetworkRequest()
body = json.dumps(payload).encode() if payload is not None else b""
getattr(blk, method)(req, *([body] if method != "get" else []))
return json.loads(bytes(blk.reply().content()) or b"null")
# 1) Login: liefert das userauth-Token = API-Key
login = request("post", "/person/login",
{"mail": "...", "password": "..."})
api_key = login["data"]["userauth"]
# 2) Layer lesen: GeoJSON FeatureCollection in EPSG:25833
fc = request("get", "/maps/p41?vkz=22017&limit=2000&offset=0",
api_key=api_key)
# 3) Layer schreiben: PUT ersetzt den kompletten Bestand dieser VKZ!
request("put", "/maps/p41/22017", payload=fc, api_key=api_key)
Die drei Stolpersteine, die das Beispiel-Plugin jeweils sauber löst:
- CRS: Die API liefert/erwartet EPSG:25833 (ETRS89/UTM33),
nicht WGS84 wie in RFC 7946 üblich. GeoJSON-Export aus QGIS daher
mit
QgsJsonExporter.setTransformGeometries(False). - Gemischte Geometrietypen: Eine FeatureCollection kann Punkte, Linien und Flächen zugleich enthalten — QGIS-Memory-Layer können das nicht. Das Plugin splittet beim Laden nach Geometrie-Familie und vereint beim Hochladen wieder (vln_karten/layer_manager.py).
- PUT ersetzt alles: Der Schreibendpunkt legt einen neuen Snapshot an und ersetzt den kompletten Layer-Bestand der VKZ. Immer den vollständigen Datensatz senden — Teilmengen löschen den Rest serverseitig.
API-Kommunikation
POST /person/login
Body: {"mail": "...", "password": "..."}
Antwort: {"data": {"userauth": "<url_token>", "id": ...}}
userauth = API-Key, danach Header "X-API-Key: <userauth>"
GET /tgen Verfahren/TGs (Auth nötig)
GET /maps/<layer>?vkz=&limit=&offset= Layer lesen, mit Paging
GET /maps/<layer>/{vkz} Layer lesen, ohne Paging
layer: umringe | p41 | st | kas | we
Auth: umringe/p41/st öffentlich, kas/we mit X-API-Key
Antwort: GeoJSON FeatureCollection in EPSG:25833
PUT /maps/<layer>/{vkz} Layer schreiben (Auth nötig)
Body: GeoJSON (ersetzt den Layer dieser VKZ, neuer Snapshot)
Antwort: {"data": {"vkz","layer","art","speicher_id"}, "status":"ok"}
Fehlerformat: RFC 7807 (application/problem+json)
Leerer vkz-Parameter (?vkz=) wird mit HTTP 400 abgelehnt.
OGC API Features — laden, bearbeiten, zurückspeichern (empfohlen)
Seit dem 07.09.2026 spricht die API OGC API Features (Part 1 Core, Part 2 CRS,
Part 3 Queryables, Part 4 CRUD) unter https://api.flurneuordnung-sachsen.de/v2/ogc.
Das ist der Weg für alle, die nur einen Manager-Login haben: QGIS lädt die Layer
nativ, und jede Änderung im Bearbeitungsmodus geht beim Speichern einzeln an die
API (POST/PUT/PATCH/DELETE je Feature) — kein Vollersetzen, kein Memory-Layer.
Ohne Plugin (QGIS 3.28+ / QGIS 4)
-
Layer → Datenquellenverwaltung → WFS / OGC API - Features → Neu
- Name:
VLN Manager, URL:https://api.flurneuordnung-sachsen.de/v2/ogc - Version: OGC API - Features
- Authentifizierung: Basic (E-Mail + Passwort des Managers) — oder Methode
API-Header mit
X-API-Key(Wert = userauth ausPOST /person/loginbzw. einvlnk_…-Schlüssel aus meinVLN → API-Keys)
- Name:
-
Verbinden → die Sammlungen des eigenen Verfahrens erscheinen, z. B.
Sammlung Inhalt Speicher-CRS umringe-27998-flaeche,p41-…,st-…,kas-…,we-…,ngg-…,biotop-…jüngster Stand des Layers (wie im Web-GIS) EPSG:25833 `vorerhebung-27998--punkt -linie -flaeche` `massnahmeblatt-27998-linie -flaeche -punkt` Jede Sammlung gibt es je Geometriefamilie (
-punkt,-linie,-flaeche): QGIS-Layer sind eintypig, die Stände des Web-GIS mischen Punkte, Linien und Flächen. Die Queryables nennen je Familie den Geometrietyp und die Felder — so lassen sich auch leere Layer direkt bearbeiten. Die Basis ohne Suffix (st-27998) ist nicht gelistet, aber lesbar. -
Layer hinzufügen → Bearbeitungsmodus → zeichnen/ändern → Layer-Änderungen speichern. QGIS schickt
Content-Crsmit; die API rechnet in PostGIS um (EPSG:25833 ↔ CRS84).
Wer nur seine Verfahren sieht: Vorsitz, Kassenbetreuer und Stellvertreter der TG;
Verbandsmitarbeiter alle (?vkz= in /ogc/collections grenzt ein).
Mit dem Plugin
Toolbar-Knopf „Alle Layer (OGC API) laden": legt nach dem Login eine
QGIS-Authentifizierungskonfiguration API-Header (X-API-Key) an — das Passwort
bleibt draußen —, holt GET /ogc/collections?vkz=… und hängt jede Sammlung als
OAPIF-Layer in eine Gruppe „VLN " (Untergruppen Vorerhebung /
Maßnahmenblätter / Verfahren). Code: vln_karten/ogc_layers.py.
from qgis.core import QgsDataSourceUri, QgsVectorLayer
uri = QgsDataSourceUri()
uri.setParam("url", "https://api.flurneuordnung-sachsen.de/v2/ogc")
uri.setParam("typename", "p41-27998-flaeche")
uri.setParam("pagingEnabled", "true")
uri.setParam("srsname", "EPSG:25833")
uri.setAuthConfigId("<authcfg-id>") # APIHeader (X-API-Key) oder Basic
layer = QgsVectorLayer(uri.uri(False), "Plan 41 · 27998 · Flächen", "OAPIF")
Regeln beim Schreiben
- Geometriefamilie: in
…-punktnur Punkte, in…-linienur Linien, in…-flaechenur Flächen (sonst HTTP 400). - Verfahrens-Layer: Änderungen landen in place im jüngsten Stand; fehlt ein Stand, legt der erste Schreibzugriff ihn an. Das Web-GIS speichert weiterhin als neuer Stand — beide treffen sich am jüngsten.
- Vorerhebung: nur Status „bearbeitung" ist schreibbar (sonst HTTP 423).
- Maßnahmenblatt:
fid = <Blatt-UUID>:<n>. Neues Feature mitblatt_uuidhängt eine Geometrie an ein Blatt; mitblatt_typ(pflanzung|wasserbau|wegebau|entsiegelung) +blatt_name(+blatt_mkz) entsteht ein neues Blatt.blatt_*-Attribute ändern die Blatt-Spalten, alles andere die Geometrie-Eigenschaften. - Fehler kommen als RFC 7807 (
application/problem+json); ohne Anmeldung 401 mitWWW-Authenticate: Basic— QGIS fragt dann selbst nach dem Login.
GET /ogc Landing Page (öffentlich)
GET /ogc/conformance Konformitätsklassen (öffentlich)
GET /ogc/collections[?vkz=] Sammlungen des Nutzers
GET /ogc/collections/{cid} Sammlung: crs, storageCrs, extent
GET /ogc/collections/{cid}/queryables
GET /ogc/collections/{cid}/items ?limit&offset&bbox&bbox-crs&crs → FeatureCollection
GET /ogc/collections/{cid}/items/{fid}
POST /ogc/collections/{cid}/items Feature | FeatureCollection → 201 {ids}
PUT /ogc/collections/{cid}/items/{fid} → 204
PATCH /ogc/collections/{cid}/items/{fid} Eigenschaften mergen, Geometrie optional → 204
DELETE /ogc/collections/{cid}/items/{fid} → 204
CRS-URIs: http://www.opengis.net/def/crs/OGC/1.3/CRS84 (Vorgabe),
http://www.opengis.net/def/crs/EPSG/0/25833
Verifiziert mit QGIS 4.2 (headless)
tools/headless_ogc_test.py treibt das installierte QGIS ohne
Oberfläche (PyQGIS, QT_QPA_PLATFORM=offscreen) gegen die API: Layer laden, Feature anlegen,
Attribut und Geometrie ändern, löschen — für einen Verfahrens-Layer und ein Maßnahmenblatt,
jeder Schritt per API gegengeprüft. Stand 07.09.2026: 0 Fehler mit QGIS 4.2.0. Was QGIS
dafür vom Server braucht (und die API liefert): service-desc-Link auf ein OpenAPI-Dokument,
Part-5-Schema für Felder/Geometrietyp, OPTIONS …/items mit Allow, PATCH als JSON Merge Patch.
Das Beispiel-Plugin (klassischer GeoJSON-Weg)
Das Plugin macht den kompletten Arbeitsablauf in der QGIS-Oberfläche erlebbar:
- Einmaliger Login (E-Mail/Passwort) — der API-Key wird in den QGIS-Einstellungen gespeichert und über QGIS-Neustarts hinweg wiederverwendet; bei 401/403 öffnet sich der Anmeldedialog erneut.
- Verfahrens-Auswahl in der Toolbar (aus
GET /tgen), gemerkt je QGIS-Projektdatei. - Buttons je Layer: Verfahrensgebiet (
umringe), Plan 41 (p41), Karte alter Stand (kas), Wertermittlung (we) — vollständig geladen über den Listen-Endpunkt mit Paging. Weitere Layer (z. B.st) sind je ein Eintrag mehr imDATASETS-Dict in vln_karten/plugin.py. - „Alle Layer (OGC API) laden“ — der neue Weg (s. o.), editierbar ohne Splitting.
- „Aktiven Layer hochladen“ vereint alle Teil-Layer des Datensatzes und schreibt per PUT zurück (mit Sicherheitsabfrage).
- Erneutes Laden ersetzt vorhandene Layer nach Rückfrage, statt sie zu stapeln — sonst würde der nächste Upload alles doppelt senden.
| Datei | Zweck |
|---|---|
| vln_karten/plugin.py | Toolbar, Aktionen, Verfahrens-Auswahl, DATASETS-Registry |
| vln_karten/api_client.py | HTTP-Client: Login, Paging-Loader, PUT, RFC-7807-Fehler |
| vln_karten/layer_manager.py | GeoJSON ↔ Memory-Layer, Geometrie-Splitting/-Vereinigung |
| vln_karten/ogc_layers.py | OGC API Features: Auth-Konfiguration (API-Header), Sammlungen → OAPIF-Layer |
| vln_karten/login_dialog.py | Anmeldedialog |
| vln_karten/metadata.txt | QGIS-Plugin-Metadaten |
Installation (zum Ausprobieren)
Voraussetzung: QGIS 3.22+ oder QGIS 4 (Qt6/PyQt6 — der Code
nutzt scoped Enums und exec()), plus ein VLN-Manager-Konto.
git clone https://entwicklung.flurneuordnung-sachsen.de/VLN_SN/API_Karte_QGISDemo.git
cd API_Karte_QGISDemo
# macOS, QGIS 4 (bei QGIS 3: "QGIS4" durch "QGIS3" ersetzen):
ln -s "$PWD/vln_karten" \
~/Library/Application\ Support/QGIS/QGIS4/profiles/default/python/plugins/vln_karten
# Linux: ~/.local/share/QGIS/QGIS4/profiles/default/python/plugins/
# Windows: %APPDATA%\QGIS\QGIS4\profiles\default\python\plugins\
Dann QGIS starten und unter Erweiterungen → Erweiterungen verwalten „VLN Karten“ aktivieren (experimentelle Erweiterungen zulassen). Beim Entwickeln hilft das Plugin Plugin Reloader — Codeänderungen wirken dann ohne QGIS-Neustart.
Hinweise für eigene Integrationen
QgsBlockingNetworkRequeststattrequests/urllibverwenden — damit greifen Proxy- und Zertifikatseinstellungen aus QGIS.- Der API-Key wird im Beispiel unverschlüsselt in QSettings abgelegt;
für Produktivcode bietet sich der QGIS-Authentifizierungsmanager an
(
QgsApplication.authManager()). - Requests laufen im Beispiel synchron (blockierend); für große
Datensätze auf
QgsNetworkAccessManagermit Tasks wechseln. - Features ohne Geometrie landen beim Laden in einem Tabellen-Layer
„ohne Geometrie“; Geometrien werden beim Hochladen als Multi-Typen
gesendet (
ST_GeomFromGeoJSONakzeptiert beides).