docs: expand pegels API documentation
This commit is contained in:
1 parent
7e9dc86446
commit
bc70066bc2
2 files changed
+238
-140
No files matched your search
+88
-3
@@ -1,5 +1,6 @@
|
||||
from fastapi import FastAPI, HTTPException
|
||||
from fastapi.responses import JSONResponse
|
||||
from pydantic import BaseModel
|
||||
import feedparser
|
||||
import re
|
||||
import html
|
||||
@@ -9,7 +10,56 @@ from urllib.error import URLError, HTTPError
|
||||
from email.utils import parsedate_to_datetime
|
||||
from typing import TypedDict, Any
|
||||
|
||||
app = FastAPI()
|
||||
app = FastAPI(
|
||||
title="Sachsen Pegel Proxy API",
|
||||
description=(
|
||||
"Liefert Stationslisten und Wasserstandsmessungen des sächsischen "
|
||||
"Hochwasser- und Wasserstands-Informationssystems (HWIMS) als JSON.\n\n"
|
||||
"Die API liest die offiziellen HWIMS-Übersichts- und RSS-Quellen aus. "
|
||||
"Messwerte und Stationsnamen können `null` sein, wenn sie in der "
|
||||
"Quelldatei fehlen oder nicht erkannt werden. Zeitstempel werden als "
|
||||
"ISO-8601-Werte mit Zeitzoneninformation ausgegeben.\n\n"
|
||||
"Die interaktive Dokumentation steht unter `/docs`, das OpenAPI-Schema "
|
||||
"unter `/openapi.json` bereit."
|
||||
),
|
||||
version="1.0.0",
|
||||
openapi_tags=[
|
||||
{
|
||||
"name": "Pegel",
|
||||
"description": "Entdecken von Pegelstationen und Abrufen ihrer Messwerte.",
|
||||
}
|
||||
],
|
||||
)
|
||||
|
||||
class PegelStation(BaseModel):
|
||||
station_id: str
|
||||
station_title: str | None
|
||||
source: str
|
||||
|
||||
class PegelIndexResponse(BaseModel):
|
||||
count: int
|
||||
total_available: int
|
||||
items: list[PegelStation]
|
||||
source: str
|
||||
fetched_at: str
|
||||
warnings: list[str] | None = None
|
||||
cache_fetched_at: str | None = None
|
||||
|
||||
class PegelEntry(BaseModel):
|
||||
timestamp: str | None
|
||||
title: str | None
|
||||
water_level_cm: float | None
|
||||
flow_m3s: float | None
|
||||
flood_alert_level: str | None
|
||||
|
||||
class PegelResponse(BaseModel):
|
||||
station_id: str
|
||||
station_title: str | None
|
||||
count: int
|
||||
latest: PegelEntry
|
||||
entries: list[PegelEntry]
|
||||
source: str
|
||||
fetched_at: str
|
||||
|
||||
BASE = "https://www.umwelt.sachsen.de/umwelt/infosysteme/hwims/portal/web/feed/wasserstand-pegel-{}"
|
||||
DISCOVERY_URL = "https://www.umwelt.sachsen.de/umwelt/infosysteme/hwims/portal/web/wasserstand-uebersicht"
|
||||
@@ -173,7 +223,25 @@ def _get_latest_for_station(station_id: str):
|
||||
}
|
||||
return latest
|
||||
|
||||
@app.get("/api/pegel")
|
||||
@app.get(
|
||||
"/api/pegel",
|
||||
response_model=PegelIndexResponse,
|
||||
tags=["Pegel"],
|
||||
summary="Pegelstationen auflisten",
|
||||
description=(
|
||||
"Liefert die auf der HWIMS-Übersichtsseite gefundenen Pegelstationen. "
|
||||
"Mit `limit` lässt sich die zurückgegebene Liste begrenzen; "
|
||||
"`total_available` enthält weiterhin die Gesamtzahl. Der Index wird "
|
||||
"15 Minuten zwischengespeichert. Ist die Quelle nicht erreichbar, "
|
||||
"wird ein vorhandener Cache verwendet und die Antwort enthält `warnings` "
|
||||
"sowie `cache_fetched_at`. Ohne verfügbaren Cache wird HTTP 502 geliefert."
|
||||
),
|
||||
response_description="Stationsliste mit Quelle und Abrufzeitpunkt.",
|
||||
responses={
|
||||
400: {"description": "`limit` ist keine positive Zahl."},
|
||||
502: {"description": "Die Discovery-Quelle ist nicht verfügbar und es gibt keinen Cache."},
|
||||
},
|
||||
)
|
||||
def list_pegel(limit: int | None = None):
|
||||
if limit is not None and limit <= 0:
|
||||
raise HTTPException(400, "Ungültiger limit-Parameter")
|
||||
@@ -219,7 +287,24 @@ def list_pegel(limit: int | None = None):
|
||||
|
||||
return JSONResponse(response)
|
||||
|
||||
@app.get("/api/pegel/{pegel_id}")
|
||||
@app.get(
|
||||
"/api/pegel/{pegel_id}",
|
||||
response_model=PegelResponse,
|
||||
tags=["Pegel"],
|
||||
summary="Messwerte eines Pegels abrufen",
|
||||
description=(
|
||||
"Liefert alle im RSS-Feed verfügbaren Einträge einer Station. "
|
||||
"`latest` ist der neueste Eintrag und entspricht `entries[0]`; "
|
||||
"die Reihenfolge von `entries` folgt dem Feed (neueste zuerst). "
|
||||
"Pegel-IDs bestehen aus mindestens sechs Ziffern. Nicht vorhandene "
|
||||
"Messwerte werden als `null` ausgegeben."
|
||||
),
|
||||
response_description="Stationsmetadaten, neuester Messwert und Feed-Historie.",
|
||||
responses={
|
||||
400: {"description": "Die Pegel-ID besteht nicht aus mindestens sechs Ziffern."},
|
||||
404: {"description": "Für diese Pegel-ID enthält der RSS-Feed keine Einträge."},
|
||||
},
|
||||
)
|
||||
def get_pegel(pegel_id: str):
|
||||
if not re.fullmatch(r"\d{6,}", pegel_id):
|
||||
raise HTTPException(400, "Ungültige Pegel-ID")
|
||||
|
||||
Reference in new issue
Block a user