Files
motia/bitbylaw/steps/advoware_proxy/advoware_api_proxy_get_step.md
2026-02-07 09:23:49 +00:00

7.5 KiB

type, category, name, version, status, tags, dependencies, emits, subscribes
type category name version status tags dependencies emits subscribes
step api Advoware Proxy GET 1.0.0 active
advoware
proxy
api
rest
services/advoware.py
redis (for token caching)

Advoware Proxy GET Step

Zweck

Universeller REST-API-Proxy für GET-Requests an die Advoware API mit automatischer Authentifizierung und Token-Management.

Kontext

Die Advoware API verwendet HMAC-512 Authentifizierung, die komplex und fehleranfällig ist. Dieser Proxy abstrahiert die Authentifizierung und bietet einen einfachen HTTP-Endpunkt für GET-Requests. Clients müssen sich nicht um Token-Management, Signatur-Generierung oder Error-Handling kümmern.

Technische Spezifikation

Config

{
    'type': 'api',
    'name': 'Advoware Proxy GET',
    'description': 'Universal proxy for Advoware API (GET)',
    'path': '/advoware/proxy',
    'method': 'GET',
    'emits': [],
    'flows': ['advoware']
}

Input

  • HTTP Method: GET
  • Path: /advoware/proxy
  • Query Parameters:
    • endpoint (required, string): Advoware API endpoint path (ohne Base-URL)
    • Alle weiteren Parameter werden an Advoware weitergeleitet

Beispiel:

GET /advoware/proxy?endpoint=employees&limit=10&offset=0

Output

Success Response (200):

{
  "status": 200,
  "body": {
    "result": {
      // Advoware API Response
    }
  }
}

Error Response (400):

{
  "status": 400,
  "body": {
    "error": "Endpoint required as query param"
  }
}

Error Response (500):

{
  "status": 500,
  "body": {
    "error": "Internal server error",
    "details": "Error message from Advoware or network"
  }
}

Events

  • Emits: Keine
  • Subscribes: Keine

Verhalten

Ablauf

  1. Extrahiere endpoint Parameter aus Query-String
  2. Validiere dass endpoint vorhanden ist
  3. Extrahiere alle anderen Query-Parameter (außer endpoint)
  4. Erstelle AdvowareAPI-Instanz
  5. Rufe api_call() mit GET-Methode auf
    • Intern: Token wird aus Redis geladen oder neu geholt
    • Intern: HMAC-Signatur wird generiert
    • Intern: Request wird an Advoware gesendet
  6. Gebe Response als JSON zurück

Fehlerbehandlung

Fehlender endpoint Parameter:

  • HTTP 400 mit Fehlermeldung
  • Request wird nicht an Advoware weitergeleitet

Advoware API Error:

  • HTTP 500 mit Details
  • Exception wird geloggt mit Stack-Trace
  • Keine Retry-Logik (fail-fast)

Token Expired (401):

  • Automatisch behandelt durch AdvowareAPI Service
  • Neuer Token wird geholt und Request wiederholt
  • Transparent für Client

Network Error:

  • HTTP 500 mit Details
  • Exception wird geloggt
  • Timeout nach ADVOWARE_API_TIMEOUT_SECONDS (default: 30s)

Side Effects

  • Keine Writes: GET-Request modifiziert keine Daten
  • Token Cache: Liest aus Redis DB 1 (advoware_access_token)
  • Logging: Schreibt INFO und ERROR logs in Motia Workbench

Abhängigkeiten

Services

  • AdvowareAPI (services/advoware.py): API-Client
    • api_call(endpoint, method='GET', params, json_data=None)
    • Handhabt Authentifizierung, Token-Caching, Error-Handling

Redis Keys (gelesen via AdvowareAPI)

  • DB 1:
    • advoware_access_token (string, TTL: 53min): Bearer Token
    • advoware_token_timestamp (string, TTL: 53min): Token Creation Time

Environment Variables

ADVOWARE_API_BASE_URL=https://www2.advo-net.net:90/
ADVOWARE_API_KEY=base64_encoded_key
ADVOWARE_APP_ID=your_app_id
ADVOWARE_USER=api_user
ADVOWARE_PASSWORD=secure_password
ADVOWARE_API_TIMEOUT_SECONDS=30
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_DB_ADVOWARE_CACHE=1

External APIs

  • Advoware API: Alle GET-fähigen Endpoints
  • Rate Limits: Unknown (keine offizielle Dokumentation)

Testing

Manual Test

# Test employee list
curl -X GET "http://localhost:3000/advoware/proxy?endpoint=employees&limit=5"

# Test appointments
curl -X GET "http://localhost:3000/advoware/proxy?endpoint=appointments?datum=2026-02-07"

# Test with error (missing endpoint)
curl -X GET "http://localhost:3000/advoware/proxy"
# Expected: 400 Bad Request

Expected Behavior

  1. Success Case:

    • Status: 200
    • Body enthält result mit Advoware-Daten
    • Logs zeigen "Proxying request to Advoware: GET {endpoint}"
  2. Error Case (missing endpoint):

    • Status: 400
    • Body: {"error": "Endpoint required as query param"}
  3. Error Case (Advoware down):

    • Status: 500
    • Body: {"error": "Internal server error", "details": "..."}
    • Logs zeigen Error mit Stack-Trace

Monitoring

Logs

[INFO] Proxying request to Advoware: GET employees
[INFO] Using cached token
[ERROR] Proxy error: ConnectionTimeout

Metrics (potentiell)

  • Request Count
  • Response Time (avg, p95, p99)
  • Error Rate
  • Cache Hit Rate (Token)

Alerts

  • Error Rate > 10% über 5 Minuten
  • Response Time > 30s (Timeout-Grenze)
  • Redis Connection Failed

Performance

Response Time

  • Cached Token: 200-500ms (typisch)
  • New Token: 1-2s (Token-Fetch + API-Call)
  • Timeout: 30s (konfigurierbar)

Throughput

  • No rate limit auf Motia-Seite
  • Advoware API: Unknown rate limits
  • Bottleneck: Advoware API Response-Zeit

Security

Secrets

  • Keine Secrets im Code
  • API Key über Environment Variable
  • Token in Redis (lokaler Zugriff nur)

Authentication

  • Client → Motia: Keine (TODO: API Key oder OAuth)
  • Motia → Advoware: HMAC-512 + Bearer Token

Data Exposure

  • GET-Requests lesen nur Daten
  • Keine PII in Logs (nur Endpoint-Pfade)
  • Response enthält alle Advoware-Daten (keine Filterung)

Änderungshistorie

Version Datum Änderung
1.0.0 2024-10-24 Initiale Implementierung

KI-Assistant Guidance

Typische Änderungen

1. Timeout erhöhen:

# In services/advoware.py, nicht im Step
Config.ADVOWARE_API_TIMEOUT_SECONDS = 60

2. Request-Parameter anpassen:

# Query-Parameter werden automatisch weitergeleitet
# Keine Code-Änderung nötig

3. Response-Transformation:

# Vor return:
result = await advoware.api_call(...)
transformed = transform_response(result)  # Neue Funktion
return {'status': 200, 'body': {'result': transformed}}

4. Caching hinzufügen:

# Vor api_call:
cache_key = f'cache:{endpoint}:{params}'
cached = redis_client.get(cache_key)
if cached:
    return {'status': 200, 'body': {'result': json.loads(cached)}}
# ... api_call ...
redis_client.set(cache_key, json.dumps(result), ex=300)

Don'ts

  • Keine synchronen Blocking-Calls: Immer await verwenden
  • Keine Hardcoded Credentials: Nur Environment Variables
  • Keine unbehandelten Exceptions: Immer try-catch
  • Kein Logging von Secrets: Keine Passwörter/Tokens loggen

Testing-Tipps

# Test mit verschiedenen Endpoints
curl "http://localhost:3000/advoware/proxy?endpoint=employees"
curl "http://localhost:3000/advoware/proxy?endpoint=appointments"
curl "http://localhost:3000/advoware/proxy?endpoint=cases"

# Test Error-Handling
curl "http://localhost:3000/advoware/proxy"  # Missing endpoint

# Test mit vielen Parametern
curl "http://localhost:3000/advoware/proxy?endpoint=employees&limit=100&offset=0&sortBy=name"