[NX-101 Issue] Refactor error handling to use consistent API error format
Replaced all inline error messages with the standardized `api_error` helper for consistent error response formatting. This improves clarity, maintainability, and ensures uniform error structures across the application. Updated logging for collector failures to include error class and switched to warning level for target unreachable scenarios.
This commit is contained in:
@@ -11,6 +11,7 @@ from sqlalchemy import desc, func, select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.core.config import get_settings
|
||||
from app.core.errors import api_error
|
||||
from app.models.models import AlertDefinition, Metric, QueryStat, Target
|
||||
from app.schemas.alert import AlertStatusItem, AlertStatusResponse
|
||||
from app.services.collector import build_target_dsn
|
||||
@@ -144,25 +145,40 @@ def get_standard_alert_reference() -> list[dict[str, str]]:
|
||||
|
||||
def validate_alert_thresholds(comparison: str, warning_threshold: float | None, alert_threshold: float) -> None:
|
||||
if comparison not in _ALLOWED_COMPARISONS:
|
||||
raise HTTPException(status_code=400, detail=f"Invalid comparison. Use one of {sorted(_ALLOWED_COMPARISONS)}")
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=api_error(
|
||||
"invalid_comparison",
|
||||
f"Invalid comparison. Use one of {sorted(_ALLOWED_COMPARISONS)}",
|
||||
),
|
||||
)
|
||||
if warning_threshold is None:
|
||||
return
|
||||
|
||||
if comparison in {"gte", "gt"} and warning_threshold > alert_threshold:
|
||||
raise HTTPException(status_code=400, detail="For gte/gt, warning_threshold must be <= alert_threshold")
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=api_error("invalid_thresholds", "For gte/gt, warning_threshold must be <= alert_threshold"),
|
||||
)
|
||||
if comparison in {"lte", "lt"} and warning_threshold < alert_threshold:
|
||||
raise HTTPException(status_code=400, detail="For lte/lt, warning_threshold must be >= alert_threshold")
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=api_error("invalid_thresholds", "For lte/lt, warning_threshold must be >= alert_threshold"),
|
||||
)
|
||||
|
||||
|
||||
def validate_alert_sql(sql_text: str) -> str:
|
||||
sql = sql_text.strip().rstrip(";")
|
||||
lowered = sql.lower().strip()
|
||||
if not lowered.startswith("select"):
|
||||
raise HTTPException(status_code=400, detail="Alert SQL must start with SELECT")
|
||||
raise HTTPException(status_code=400, detail=api_error("invalid_alert_sql", "Alert SQL must start with SELECT"))
|
||||
if _FORBIDDEN_SQL_WORDS.search(lowered):
|
||||
raise HTTPException(status_code=400, detail="Only read-only SELECT statements are allowed")
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=api_error("invalid_alert_sql", "Only read-only SELECT statements are allowed"),
|
||||
)
|
||||
if ";" in sql:
|
||||
raise HTTPException(status_code=400, detail="Only a single SQL statement is allowed")
|
||||
raise HTTPException(status_code=400, detail=api_error("invalid_alert_sql", "Only a single SQL statement is allowed"))
|
||||
return sql
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user