# Schritt 4: Routen erstellen [← Zurück: Feature-Logik implementieren](04-feature-logic.md) | [Weiter: Router registrieren →](06-router-registration.md) **Datei:** `modules/routes/routeRealEstate.py` Die Routen definieren die REST-API-Endpunkte für das Feature. Das Feature arbeitet **stateless** ohne Session-Management. ## Route-Struktur ``` /api/realestate/ ├── POST /command → Natürliche Sprache → CRUD-Operation └── POST /query → Direkte SQL-Query ``` ## Beispiel-Implementierung: ```python """ Real Estate routes for the backend API. Implements stateless endpoints for real estate database operations with AI-powered natural language processing. """ import logging from typing import Optional, Dict, Any from fastapi import APIRouter, HTTPException, Depends, Body, Request from modules.security.auth import limiter, getCurrentUser from modules.datamodels.datamodelUam import User from modules.features.realEstate.mainRealEstate import ( processNaturalLanguageCommand, executeDirectQuery, ) # Configure logger logger = logging.getLogger(__name__) # Create router for real estate endpoints router = APIRouter( prefix="/api/realestate", tags=["Real Estate"], responses={404: {"description": "Not found"}} ) # ===== Stateless Command Endpoint ===== @router.post("/command", response_model=Dict[str, Any]) @limiter.limit("120/minute") async def process_command( request: Request, userInput: str = Body(..., embed=True, description="Natural language command"), currentUser: User = Depends(getCurrentUser) ) -> Dict[str, Any]: """ Process natural language command and execute corresponding CRUD operation. Uses AI to analyze user intent and extract parameters, then executes the appropriate CRUD operation. Works stateless without session management. Example user inputs: - "Erstelle ein neues Projekt namens 'Hauptstrasse 42'" - "Zeige mir alle Projekte in Zürich" - "Aktualisiere Projekt XYZ mit Status 'Planung'" - "Lösche Parzelle ABC" - "SELECT * FROM Projekt WHERE plz = '8000'" Returns: { "success": true, "intent": "CREATE|READ|UPDATE|DELETE|QUERY", "entity": "Projekt|Parzelle|...|null", "result": {...} } """ try: result = await processNaturalLanguageCommand( currentUser=currentUser, userInput=userInput ) return result except ValueError as e: logger.error(f"Validation error: {str(e)}") raise HTTPException( status_code=400, detail=str(e) ) except Exception as e: logger.error(f"Error processing command: {str(e)}") raise HTTPException( status_code=500, detail=str(e) ) # ===== Stateless Query Endpoint ===== @router.post("/query", response_model=Dict[str, Any]) @limiter.limit("120/minute") async def execute_query( request: Request, queryText: str = Body(..., embed=True, description="SQL query text"), parameters: Optional[Dict[str, Any]] = Body(None, embed=True, description="Optional query parameters for parameterized queries"), currentUser: User = Depends(getCurrentUser) ) -> Dict[str, Any]: """ Execute a direct SQL query without session management. Executes the query directly and returns the result. No query history is saved. WARNING: This endpoint executes raw SQL queries. Ensure proper validation and sanitization on the frontend. Consider implementing query whitelisting or only allowing SELECT statements for production use. Returns: { "status": "success", "rows": [...], "columns": [...], "rowCount": 15, "executionTime": 0.123 } """ try: result = await executeDirectQuery( currentUser=currentUser, queryText=queryText, parameters=parameters, ) return result except ValueError as e: logger.error(f"Validation error: {str(e)}") raise HTTPException( status_code=400, detail=str(e) ) except Exception as e: logger.error(f"Error executing query: {str(e)}") raise HTTPException( status_code=500, detail=str(e) ) ``` ## Wichtige Punkte: ### 1. Stateless Design - **Keine Session-Management**: Alle Endpunkte arbeiten stateless - **Direkte Verarbeitung**: User-Input wird direkt verarbeitet und Ergebnis zurückgegeben - **Keine History**: Queries werden nicht gespeichert (kann optional später hinzugefügt werden) ### 2. API-Endpunkte **`POST /api/realestate/command`** - Verarbeitet natürliche Sprache - Nutzt AI für Intent-Analyse - Führt CRUD-Operationen aus - Gibt Ergebnis direkt zurück **`POST /api/realestate/query`** - Führt direkte SQL-Queries aus - Keine Session notwendig - Gibt Query-Ergebnis direkt zurück ### 3. Sicherheit - **Rate Limiting**: `@limiter.limit("120/minute")` für API-Schutz - **Authentication**: `Depends(getCurrentUser)` für alle Endpunkte - **Query-Validierung**: WICHTIG - Validieren Sie SQL-Queries vor Ausführung - **MandateId-Filter**: Wird automatisch durch Interfaces angewendet ### 4. Error Handling - Umfassendes Error Handling mit HTTPException - Unterschiedliche Status-Codes: 400 (Validation), 404 (Not Found), 500 (Server Error) - Detaillierte Fehlermeldungen für Debugging ### 5. Response-Struktur **Command-Endpunkt:** ```json { "success": true, "intent": "CREATE", "entity": "Projekt", "result": { "operation": "CREATE", "entity": "Projekt", "result": { "id": "projekt_123", "label": "Hauptstrasse 42", ... } } } ``` **Query-Endpunkt:** ```json { "status": "success", "rows": [ {"id": "...", "label": "...", ...} ], "columns": ["id", "label", ...], "rowCount": 15, "executionTime": 0.123 } ``` --- ## Beispiel-Requests ### Command-Endpunkt ```bash # CREATE Operation POST /api/realestate/command Content-Type: application/json Authorization: Bearer { "userInput": "Erstelle ein neues Projekt namens 'Hauptstrasse 42'" } # READ Operation POST /api/realestate/command { "userInput": "Zeige mir alle Projekte in Zürich" } # UPDATE Operation POST /api/realestate/command { "userInput": "Aktualisiere Projekt XYZ mit Status 'Planung'" } # DELETE Operation POST /api/realestate/command { "userInput": "Lösche Parzelle ABC" } # QUERY Operation (SQL wird erkannt) POST /api/realestate/command { "userInput": "SELECT * FROM Projekt WHERE plz = '8000'" } ``` ### Query-Endpunkt ```bash # Direkte SQL-Query POST /api/realestate/query Content-Type: application/json Authorization: Bearer { "queryText": "SELECT * FROM Projekt WHERE plz = '8000'" } # Parameterized Query POST /api/realestate/query { "queryText": "SELECT * FROM Projekt WHERE plz = $1", "parameters": {"$1": "8000"} } ``` --- ## Flow: Route → Feature-Logik ### Command-Endpunkt Flow ``` POST /api/realestate/command ↓ routeRealEstate.process_command() ↓ getCurrentUser() # Auth ↓ processNaturalLanguageCommand(currentUser, userInput) ↓ mainRealEstate.processNaturalLanguageCommand() ↓ analyzeUserIntent() → executeIntentBasedOperation() ↓ return Dict mit Ergebnis ``` ### Query-Endpunkt Flow ``` POST /api/realestate/query ↓ routeRealEstate.execute_query() ↓ getCurrentUser() # Auth ↓ executeDirectQuery(currentUser, queryText, parameters) ↓ mainRealEstate.executeDirectQuery() ↓ getChatInterface(currentUser) ↓ RealEstateChatObjects.executeQuery(queryText) ↓ DatabaseConnector.executeQuery(sql) ↓ return Dict mit rows, columns, rowCount ``` --- ## Vorteile des stateless Ansatzes - **Einfachheit**: Kein Session-Management notwendig - **Performance**: Weniger Datenbank-Operationen pro Request - **Skalierbarkeit**: Stateless Requests sind einfacher zu skalieren - **Flexibilität**: Jeder Request ist unabhängig - **Schnell**: Direkte Verarbeitung ohne Overhead --- [← Zurück: Feature-Logik implementieren](04-feature-logic.md) | [Weiter: Router registrieren →](06-router-registration.md)