smlflg's picture
Initial public upload from Projekte/Sidecar-Workspace (part 4)
e6b2bd6 verified
|
Raw History Blame Contribute Delete
9.61 kB

FastAPI β€” Referenz fuer das Keeper System

Was macht FastAPI hier?

FastAPI ist unser REST-API-Layer β€” die Schnittstelle zwischen der Aussenwelt und dem System. Ueber die API kann man:

  • Produkte zur Ueberwachung hinzufuegen (Watches)
  • Preise manuell pruefen
  • Deals suchen (via Keepa oder Elasticsearch)
  • Preis-Statistiken und -Historie abrufen
  • System-Status und Token-Budget einsehen

Version: 2.0.0 Port: 8000 Datei: src/api/main.py


Swagger UI

FastAPI generiert automatisch eine interaktive API-Dokumentation:

URL: http://localhost:8000/docs

Dort kannst du jeden Endpoint direkt im Browser testen.


Startup (Lifespan)

@asynccontextmanager
async def lifespan(app: FastAPI):
    # Beim Start:
    await init_db()          # PostgreSQL Tabellen erstellen
    await es_service.connect()  # Elasticsearch verbinden

    yield  # App laeuft

    # Beim Shutdown:
    await es_service.close()

Was passiert beim Start:

  1. Datenbank-Tabellen werden erstellt (falls nicht vorhanden)
  2. Elasticsearch-Verbindung wird hergestellt + Indices erstellt
  3. App ist bereit

CORS Middleware

app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://localhost:5601", "http://localhost:3000"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

Erlaubt Zugriffe von:

  • localhost:5601 β€” Kibana Dashboards
  • localhost:3000 β€” Frontend (falls vorhanden)

Endpoint-Referenz

Health & Status

GET /health

System-Health-Check. Zeigt Token-Status und Watch-Anzahl.

curl http://localhost:8000/health
{
  "status": "healthy",
  "timestamp": "2026-02-20T12:00:00",
  "tokens_available": 150,
  "watches_count": 12
}

GET /api/v1/status

Detaillierter System-Status mit Token Bucket und Rate Limit Info.

curl http://localhost:8000/api/v1/status
{
  "system": "healthy",
  "version": "2.0.0",
  "token_bucket": {
    "tokens_available": 150,
    "tokens_per_minute": 200,
    "last_refill": "2026-02-20T11:59:00",
    "total_tokens_consumed": 450
  },
  "rate_limit": {
    "tokens_available": 150,
    "refill_in_seconds": 45
  }
}

Watches (Preis-Ueberwachung)

GET /api/v1/watches?user_id=UUID

Alle aktiven Watches eines Users auflisten.

curl "http://localhost:8000/api/v1/watches?user_id=550e8400-e29b-41d4-a716-446655440000"
[
  {
    "id": "uuid...",
    "asin": "B07W6JN8V8",
    "target_price": 45.00,
    "current_price": 49.99,
    "status": "ACTIVE",
    "last_checked_at": "2026-02-20T06:00:00",
    "created_at": "2026-02-15T10:30:00"
  }
]

POST /api/v1/watches?user_id=UUID

Neue Watch erstellen. Fragt sofort den aktuellen Preis bei Keepa ab.

curl -X POST "http://localhost:8000/api/v1/watches?user_id=UUID" \
  -H "Content-Type: application/json" \
  -d '{"asin": "B07W6JN8V8", "target_price": 45.00}'

Request Body:

{
  "asin": "B07W6JN8V8",     // Genau 10 Zeichen
  "target_price": 45.00      // EUR, muss > 0 sein
}

Response: Watch-Objekt mit aktuellem Preis (201 Created)

Fehler:

  • 400 β€” Ungueltige ASIN oder target_price
  • 500 β€” Keepa API Fehler

DELETE /api/v1/watches/{watch_id}?user_id=UUID

Watch loeschen (Soft Delete β†’ Status wird INACTIVE).

curl -X DELETE "http://localhost:8000/api/v1/watches/uuid...?user_id=UUID"

Preis-Check

POST /api/v1/price/check

Manueller Preis-Check fuer eine einzelne ASIN. Ruft Keepa API auf.

curl -X POST http://localhost:8000/api/v1/price/check \
  -H "Content-Type: application/json" \
  -d '{"asin": "B07W6JN8V8"}'
{
  "asin": "B07W6JN8V8",
  "title": "Logitech K380 Multi-Device Bluetooth Tastatur",
  "current_price": 49.99,
  "list_price": 59.99,
  "rating": 4.5,
  "category": "340843031",
  "timestamp": "2026-02-20T12:00:00"
}

Kosten: ~15 Keepa-Tokens

POST /api/v1/price/check-all

Alle aktiven Watches pruefen. Wie ein manueller Scheduler-Durchlauf.

curl -X POST http://localhost:8000/api/v1/price/check-all
{
  "status": "completed",
  "watches_checked": 12,
  "price_changes": 3,
  "alerts_triggered": 1,
  "timestamp": "2026-02-20T12:05:00"
}

Achtung: Kostet 15 Tokens PRO Watch. Bei 50 Watches = 750 Tokens.


Deals

POST /api/v1/deals/search

Deal-Suche via Keepa API (oder Product-Fallback).

curl -X POST http://localhost:8000/api/v1/deals/search \
  -H "Content-Type: application/json" \
  -d '{
    "categories": ["340843031"],
    "min_discount": 20,
    "max_discount": 80,
    "min_price": 15,
    "max_price": 200,
    "min_rating": 4.0
  }'
[
  {
    "asin": "B07W6JN8V8",
    "title": "Logitech K380 QWERTZ",
    "current_price": 39.99,
    "list_price": 59.99,
    "discount_percent": 33.4,
    "rating": 4.5,
    "reviews": 1847,
    "prime_eligible": true,
    "url": "https://amazon.de/dp/B07W6JN8V8",
    "deal_score": 8.7,
    "source": "product_api"
  }
]

Fehler:

  • 429 β€” Token Limit erreicht
  • 403 β€” Deal-API nicht verfuegbar (NoDealAccessError)

POST /api/v1/deals/es-search

Deal-Suche via Elasticsearch (Volltextsuche + Aggregationen).

curl -X POST http://localhost:8000/api/v1/deals/es-search \
  -H "Content-Type: application/json" \
  -d '{
    "query": "logitech mechanisch",
    "min_discount": 15,
    "min_rating": 4.0,
    "page": 0,
    "size": 10
  }'
{
  "total": 47,
  "deals": [
    {
      "asin": "B07W6JN8V8",
      "title": "Logitech MX Mechanical",
      "current_price": 119.99,
      "discount_percent": 25.0,
      "_score": 12.5
    }
  ],
  "aggregations": {
    "by_category": { ... },
    "by_domain": { ... },
    "price_stats": { "min": 15.99, "max": 299.99, "avg": 65.50 },
    "discount_stats": { "min": 15.0, "max": 70.0, "avg": 32.5 }
  }
}

Features:

  • multi_match mit Fuzziness (Tippfehler-tolerant)
  • title wird 3x hoeher gewichtet als description
  • Aggregationen fuer Dashboard-Widgets
  • Sortierung: deal_score desc, dann timestamp desc

GET /api/v1/deals/aggregations?min_discount=20&min_rating=4

Deal-Statistiken aus Elasticsearch.

POST /api/v1/deals/index

Manuell ein Deal-Dokument in Elasticsearch indexieren.


Preis-Historie

GET /api/v1/prices/{asin}/history?days=30

Preishistorie aus PostgreSQL (price_history Tabelle).

curl "http://localhost:8000/api/v1/prices/B07W6JN8V8/history?days=30"
{
  "asin": "B07W6JN8V8",
  "history": [
    {"price": 49.99, "recorded_at": "2026-02-01T12:00:00", "source": "kafka_deals"},
    {"price": 45.99, "recorded_at": "2026-02-05T12:00:00", "source": null},
    {"price": 39.99, "recorded_at": "2026-02-10T12:00:00", "source": "kafka_deals"}
  ],
  "count": 3,
  "period_days": 30
}

GET /api/v1/prices/{asin}/stats

Preis-Statistiken aus Elasticsearch (Aggregationen).

curl "http://localhost:8000/api/v1/prices/B07W6JN8V8/stats"
{
  "asin": "B07W6JN8V8",
  "min": 29.99,
  "max": 59.99,
  "avg": 42.50,
  "current": 39.99,
  "data_points": 47,
  "price_over_time": [
    {"date": "2026-02-01", "avg_price": 49.99, "min_price": 45.99, "max_price": 52.99}
  ]
}

Token & Rate Limit

GET /api/v1/tokens

Token Bucket Status (intern, nicht Keepa API).

GET /api/v1/rate-limit

Rate Limit Status direkt von der Keepa API.


Pydantic Models

Alle Request/Response Models sind in src/api/main.py definiert:

Model Verwendung
WatchCreateRequest POST /watches Body
WatchResponse GET/POST /watches Response
WatchDeleteResponse DELETE /watches Response
DealSearchRequest POST /deals/search Body
DealResponse POST /deals/search Response Items
ElasticsearchDealSearchRequest POST /deals/es-search Body
ElasticsearchDealResponse POST /deals/es-search Response
HealthResponse GET /health Response
PriceCheckRequest POST /price/check Body
PriceCheckResponse POST /price/check Response
TriggerCheckResponse POST /price/check-all Response

Konfiguration

In src/config.py:

app_name: str = "Keeper System"
debug: bool = False
log_level: str = "INFO"

In docker-compose.yml:

app:
  build: .
  ports:
    - "8000:8000"
  command: uvicorn src.api.main:app --host 0.0.0.0 --port 8000

Fehlerbehandlung

HTTP Status Bedeutung Wann
200 OK Erfolgreiche Abfrage
201 Created Watch erstellt
400 Bad Request Ungueltige ASIN, fehlende Parameter
403 Forbidden Deal-API nicht im Plan
404 Not Found ASIN nicht gefunden, Watch nicht gefunden
429 Too Many Requests Keepa Token Limit
500 Internal Error Unerwarteter Fehler
503 Service Unavailable Elasticsearch nicht erreichbar

Testen

# Health Check
curl http://localhost:8000/health

# Watch erstellen
curl -X POST "http://localhost:8000/api/v1/watches?user_id=00000000-0000-0000-0000-000000000001" \
  -H "Content-Type: application/json" \
  -d '{"asin": "B07W6JN8V8", "target_price": 45.00}'

# Preis checken
curl -X POST http://localhost:8000/api/v1/price/check \
  -H "Content-Type: application/json" \
  -d '{"asin": "B07W6JN8V8"}'

# Elasticsearch Deal-Suche
curl -X POST http://localhost:8000/api/v1/deals/es-search \
  -H "Content-Type: application/json" \
  -d '{"query": "cherry tastatur", "min_discount": 10}'