Immer noch nicht richtig gut, also noch **WIP**
This commit is contained in:
514
api/README.md
Normal file
514
api/README.md
Normal file
@@ -0,0 +1,514 @@
|
||||
# Wetterstation API
|
||||
|
||||
REST API zum Abrufen von Wetterdaten aus der PostgreSQL-Datenbank.
|
||||
|
||||
## Übersicht
|
||||
|
||||
Die API basiert auf **FastAPI** und bietet Endpunkte für aktuelle Wetterdaten, historische Zeitreihen, Statistiken und aggregierte Daten.
|
||||
|
||||
- **Version:** 1.0.0
|
||||
- **Framework:** FastAPI mit Uvicorn
|
||||
- **Datenbank:** PostgreSQL
|
||||
- **Interaktive API-Dokumentation:** `/docs` (Swagger UI) oder `/redoc` (ReDoc)
|
||||
|
||||
## Starten der API
|
||||
|
||||
### Lokal (Development)
|
||||
|
||||
```bash
|
||||
cd api
|
||||
python main.py
|
||||
```
|
||||
|
||||
Die API läuft dann auf `http://localhost:8000`
|
||||
|
||||
### Docker (Production)
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
## Umgebungsvariablen
|
||||
|
||||
Die API benötigt folgende Umgebungsvariablen (definiert in `.env`):
|
||||
|
||||
```env
|
||||
DB_HOST=localhost
|
||||
DB_PORT=5432
|
||||
DB_NAME=wetterstation
|
||||
DB_USER=wetterstation_user
|
||||
DB_PASSWORD=<passwort>
|
||||
```
|
||||
|
||||
## Endpunkte
|
||||
|
||||
### 📋 General
|
||||
|
||||
#### `GET /`
|
||||
**Root-Endpunkt mit API-Informationen**
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"message": "Wetterstation API",
|
||||
"version": "1.0.0",
|
||||
"docs": "/docs"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### `GET /health`
|
||||
**Health Check - Prüft API- und Datenbankstatus**
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"database": "connected",
|
||||
"timestamp": "2026-03-23T14:30:00"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 🌡️ Weather Data
|
||||
|
||||
#### `GET /weather/latest`
|
||||
**Gibt die neuesten Wetterdaten zurück**
|
||||
|
||||
**Response Model:** `WeatherData`
|
||||
|
||||
**Beispiel:**
|
||||
```json
|
||||
{
|
||||
"id": 123456,
|
||||
"datetime": "2026-03-23T14:30:00Z",
|
||||
"temperature": 15.5,
|
||||
"humidity": 65,
|
||||
"pressure": 1013.2,
|
||||
"wind_speed": 12.5,
|
||||
"wind_gust": 18.7,
|
||||
"wind_dir": 225.0,
|
||||
"rain": 0.0,
|
||||
"rain_rate": 0.0,
|
||||
"received_at": "2026-03-23T14:30:05"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### `GET /weather/current`
|
||||
**Alias für `/weather/latest` - gibt aktuelle Wetterdaten zurück**
|
||||
|
||||
---
|
||||
|
||||
#### `GET /weather/history`
|
||||
**Gibt historische Wetterdaten der letzten X Stunden zurück**
|
||||
|
||||
**Query Parameter:**
|
||||
- `hours` (optional): Anzahl Stunden zurück (1-168, default: 24)
|
||||
- `limit` (optional): Maximale Anzahl Datensätze (1-10000, default: 1000)
|
||||
|
||||
**Beispiel:**
|
||||
```bash
|
||||
GET /weather/history?hours=48&limit=500
|
||||
```
|
||||
|
||||
**Response:** Array von `WeatherData`
|
||||
|
||||
---
|
||||
|
||||
#### `GET /weather/range`
|
||||
**Gibt Wetterdaten für einen bestimmten Zeitraum zurück**
|
||||
|
||||
**Query Parameter:**
|
||||
- `start` (erforderlich): Startdatum (ISO 8601)
|
||||
- `end` (erforderlich): Enddatum (ISO 8601)
|
||||
- `limit` (optional): Maximale Anzahl Datensätze (1-50000, default: 10000)
|
||||
|
||||
**Beispiel:**
|
||||
```bash
|
||||
GET /weather/range?start=2026-03-01T00:00:00Z&end=2026-03-23T23:59:59Z&limit=5000
|
||||
```
|
||||
|
||||
**Response:** Array von `WeatherData`
|
||||
|
||||
---
|
||||
|
||||
#### `GET /weather/temperature`
|
||||
**Gibt nur Temperatur-Zeitreihen zurück (optimiert für Diagramme)**
|
||||
|
||||
**Query Parameter:**
|
||||
- `hours` (optional): Anzahl Stunden zurück (1-168, default: 24)
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"datetime": "2026-03-23T14:00:00Z",
|
||||
"temperature": 15.3
|
||||
},
|
||||
{
|
||||
"datetime": "2026-03-23T14:05:00Z",
|
||||
"temperature": 15.5
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### `GET /weather/wind`
|
||||
**Gibt nur Wind-Daten zurück (Geschwindigkeit, Richtung, Böen)**
|
||||
|
||||
**Query Parameter:**
|
||||
- `hours` (optional): Anzahl Stunden zurück (1-168, default: 24)
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"datetime": "2026-03-23T14:00:00Z",
|
||||
"wind_speed": 12.5,
|
||||
"wind_gust": 18.7,
|
||||
"wind_dir": 225.0
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### `GET /weather/rain`
|
||||
**Gibt nur Regen-Daten zurück**
|
||||
|
||||
**Query Parameter:**
|
||||
- `hours` (optional): Anzahl Stunden zurück (1-168, default: 24)
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"datetime": "2026-03-23T14:00:00Z",
|
||||
"rain": 0.5,
|
||||
"rain_rate": 2.3
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 📊 Statistics
|
||||
|
||||
#### `GET /weather/stats`
|
||||
**Gibt aggregierte Statistiken für den angegebenen Zeitraum zurück**
|
||||
|
||||
**Query Parameter:**
|
||||
- `hours` (optional): Zeitraum in Stunden (1-168, default: 24)
|
||||
|
||||
**Response Model:** `WeatherStats`
|
||||
|
||||
**Beispiel:**
|
||||
```json
|
||||
{
|
||||
"avg_temperature": 15.2,
|
||||
"min_temperature": 8.5,
|
||||
"max_temperature": 22.1,
|
||||
"avg_humidity": 65.3,
|
||||
"avg_pressure": 1013.5,
|
||||
"avg_wind_speed": 10.2,
|
||||
"max_wind_gust": 28.5,
|
||||
"total_rain": 3.2,
|
||||
"data_points": 288
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### `GET /weather/daily`
|
||||
**Gibt tägliche Statistiken für die letzten X Tage zurück**
|
||||
|
||||
**Query Parameter:**
|
||||
- `days` (optional): Anzahl Tage zurück (1-90, default: 7)
|
||||
|
||||
**Response:** Array von `WeatherStats` mit `date` Feld
|
||||
|
||||
---
|
||||
|
||||
### 📈 Aggregated Data
|
||||
|
||||
Die aggregierten Endpunkte sind optimiert für Langzeit-Visualisierungen und reduzieren die Datenmenge durch Mittelwertbildung.
|
||||
|
||||
#### `GET /weather/hourly-aggregated`
|
||||
**Gibt stündlich aggregierte Wetterdaten zurück (Stundenmittel)**
|
||||
|
||||
**Query Parameter:**
|
||||
- `days` (optional): Anzahl Tage zurück (1-60, default: 7)
|
||||
|
||||
**Response:** Array von `WeatherData` (stündlich aggregiert)
|
||||
|
||||
**Verwendung:** Ideal für 7-Tage- und 30-Tage-Ansichten
|
||||
|
||||
---
|
||||
|
||||
#### `GET /weather/daily-aggregated`
|
||||
**Gibt täglich aggregierte Wetterdaten zurück (Tagesmittel)**
|
||||
|
||||
**Query Parameter:**
|
||||
- `days` (optional): Anzahl Tage zurück (1-730, default: 365)
|
||||
|
||||
**Response:** Array von `WeatherData` (täglich aggregiert)
|
||||
|
||||
**Besonderheit:** Bei `days >= 365` werden automatisch **alle verfügbaren Daten** zurückgegeben (nicht nur die letzten 365 Tage).
|
||||
|
||||
**Verwendung:** Ideal für Jahresübersicht (365-Tage-Ansicht)
|
||||
|
||||
---
|
||||
|
||||
#### `GET /weather/rain-daily`
|
||||
**Gibt tägliche Regensummen zurück**
|
||||
|
||||
**Query Parameter:**
|
||||
- `days` (optional): Anzahl Tage zurück (1-365, default: 30)
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"date": "2026-03-23T00:00:00Z",
|
||||
"total_rain": 5.2
|
||||
},
|
||||
{
|
||||
"date": "2026-03-22T00:00:00Z",
|
||||
"total_rain": 0.0
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
**Verwendung:** Ideal für 7-Tage- und 30-Tage-Regen-Diagramme
|
||||
|
||||
---
|
||||
|
||||
#### `GET /weather/rain-weekly`
|
||||
**Gibt wöchentliche Regensummen zurück (Woche = Mo-So)**
|
||||
|
||||
**Query Parameter:**
|
||||
- `days` (optional): Anzahl Tage zurück (1-730, default: 365)
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"week_start": "2026-03-17T00:00:00Z",
|
||||
"total_rain": 12.5
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
**Besonderheit:** Bei `days >= 365` werden automatisch **alle verfügbaren Daten** zurückgegeben.
|
||||
|
||||
**Verwendung:** Ideal für Jahresübersicht (365-Tage-Ansicht)
|
||||
|
||||
---
|
||||
|
||||
## Datenmodelle
|
||||
|
||||
### WeatherData
|
||||
|
||||
```typescript
|
||||
{
|
||||
id: number
|
||||
datetime: string (ISO 8601)
|
||||
temperature: number | null // °C
|
||||
humidity: number | null // %
|
||||
pressure: number | null // hPa
|
||||
wind_speed: number | null // km/h (konvertiert von mph)
|
||||
wind_gust: number | null // km/h (konvertiert von mph)
|
||||
wind_dir: number | null // Grad (0-360)
|
||||
rain: number | null // mm
|
||||
rain_rate: number | null // mm/h
|
||||
received_at: string (ISO 8601)
|
||||
}
|
||||
```
|
||||
|
||||
### WeatherStats
|
||||
|
||||
```typescript
|
||||
{
|
||||
avg_temperature: number | null
|
||||
min_temperature: number | null
|
||||
max_temperature: number | null
|
||||
avg_humidity: number | null
|
||||
avg_pressure: number | null
|
||||
avg_wind_speed: number | null
|
||||
max_wind_gust: number | null
|
||||
total_rain: number | null
|
||||
data_points: number
|
||||
}
|
||||
```
|
||||
|
||||
### HealthResponse
|
||||
|
||||
```typescript
|
||||
{
|
||||
status: string // "ok" | "error"
|
||||
database: string // "connected" | "disconnected"
|
||||
timestamp: string (ISO 8601)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Einheitenkonvertierung
|
||||
|
||||
Die API konvertiert automatisch folgende Einheiten aus der Datenbank:
|
||||
|
||||
| Wert | Datenbank | API-Ausgabe |
|
||||
|------|-----------|-------------|
|
||||
| Windgeschwindigkeit | mph | km/h (× 1.60934) |
|
||||
| Windböen | mph | km/h (× 1.60934) |
|
||||
| Temperatur | °C | °C (unverändert) |
|
||||
| Luftdruck | hPa | hPa (unverändert) |
|
||||
| Regen | mm | mm (unverändert) |
|
||||
|
||||
---
|
||||
|
||||
## CORS
|
||||
|
||||
Die API erlaubt CORS-Anfragen von allen Origins (`allow_origins=["*"]`). In Production sollte dies auf spezifische Domains eingeschränkt werden.
|
||||
|
||||
---
|
||||
|
||||
## Fehlerbehandlung
|
||||
|
||||
### HTTP Status Codes
|
||||
|
||||
- `200 OK` - Erfolgreiche Anfrage
|
||||
- `400 Bad Request` - Ungültige Parameter
|
||||
- `404 Not Found` - Keine Daten gefunden
|
||||
- `500 Internal Server Error` - Datenbankfehler
|
||||
|
||||
### Fehler-Response
|
||||
|
||||
```json
|
||||
{
|
||||
"detail": "Keine Daten verfügbar"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Interaktive Dokumentation
|
||||
|
||||
FastAPI generiert automatisch eine interaktive API-Dokumentation:
|
||||
|
||||
- **Swagger UI:** [http://localhost:8000/docs](http://localhost:8000/docs)
|
||||
- **ReDoc:** [http://localhost:8000/redoc](http://localhost:8000/redoc)
|
||||
|
||||
Dort können alle Endpunkte direkt getestet werden.
|
||||
|
||||
---
|
||||
|
||||
## Beispiele
|
||||
|
||||
### cURL
|
||||
|
||||
```bash
|
||||
# Aktuelle Wetterdaten abrufen
|
||||
curl http://localhost:8000/weather/current
|
||||
|
||||
# Letzte 48 Stunden
|
||||
curl "http://localhost:8000/weather/history?hours=48"
|
||||
|
||||
# Jahresübersicht (alle verfügbaren Daten)
|
||||
curl "http://localhost:8000/weather/daily-aggregated?days=365"
|
||||
|
||||
# Statistiken für letzte 7 Tage
|
||||
curl "http://localhost:8000/weather/stats?hours=168"
|
||||
```
|
||||
|
||||
### JavaScript (Fetch)
|
||||
|
||||
```javascript
|
||||
// Aktuelle Wetterdaten
|
||||
const response = await fetch('http://localhost:8000/weather/current')
|
||||
const data = await response.json()
|
||||
console.log(`Temperatur: ${data.temperature}°C`)
|
||||
|
||||
// Tägliche Aggregation für 365 Tage
|
||||
const yearData = await fetch('http://localhost:8000/weather/daily-aggregated?days=365')
|
||||
const year = await yearData.json()
|
||||
console.log(`${year.length} Tage verfügbar`)
|
||||
```
|
||||
|
||||
### Python (requests)
|
||||
|
||||
```python
|
||||
import requests
|
||||
|
||||
# Aktuelle Daten
|
||||
response = requests.get('http://localhost:8000/weather/current')
|
||||
data = response.json()
|
||||
print(f"Temperatur: {data['temperature']}°C")
|
||||
|
||||
# Statistiken
|
||||
stats = requests.get('http://localhost:8000/weather/stats?hours=24')
|
||||
print(f"Durchschnittstemperatur: {stats.json()['avg_temperature']}°C")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Entwicklung
|
||||
|
||||
### Abhängigkeiten installieren
|
||||
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
### Server starten (Development mit Auto-Reload)
|
||||
|
||||
```bash
|
||||
uvicorn main:app --reload --host 0.0.0.0 --port 8000
|
||||
```
|
||||
|
||||
### Logging
|
||||
|
||||
Die API verwendet Python's `logging`-Modul. Log-Level: `INFO`
|
||||
|
||||
---
|
||||
|
||||
## Deployment
|
||||
|
||||
Die API wird als Docker-Container deployed. Siehe `Dockerfile` und `docker-compose.yml` im Hauptverzeichnis.
|
||||
|
||||
### Docker Image bauen
|
||||
|
||||
```bash
|
||||
docker build -t wetterstation-api ./api
|
||||
```
|
||||
|
||||
### Container starten
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
-p 8000:8000 \
|
||||
-e DB_HOST=db \
|
||||
-e DB_USER=wetterstation_user \
|
||||
-e DB_PASSWORD=<passwort> \
|
||||
wetterstation-api
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Performance-Tipps
|
||||
|
||||
1. **Aggregierte Endpunkte verwenden** für Langzeit-Visualisierungen (reduziert Datenmenge)
|
||||
2. **Limit-Parameter** nutzen, um nur benötigte Datenmenge abzurufen
|
||||
3. **Spezifische Endpunkte** verwenden (`/weather/temperature` statt `/weather/history` wenn nur Temperatur benötigt wird)
|
||||
4. **Caching** auf Client-Seite implementieren für historische Daten
|
||||
|
||||
---
|
||||
|
||||
## Lizenz
|
||||
|
||||
Siehe Hauptprojekt-Repository.
|
||||
Reference in New Issue
Block a user