77from datetime import datetime
88from typing import Any
99
10- from fastapi import APIRouter , HTTPException , Request , status
10+ from fastapi import APIRouter , Request
1111from pydantic import BaseModel , Field
1212
1313from app import __version__
1414from app .config import get_settings
15+ from app .exceptions import (
16+ AuthenticationException ,
17+ ModelInferenceException ,
18+ QueryNotFoundException ,
19+ SchemaNotFoundException ,
20+ ValidationException ,
21+ )
1522from app .logging_config import get_logger
1623from app .security import limiter , validate_database_id , validate_natural_language_query
1724from db .connection import get_database
@@ -186,12 +193,9 @@ async def generate_sql(request: Request, query_request: QueryRequest) -> QueryRe
186193 errors = query_errors ,
187194 database_id = query_request .database_id ,
188195 )
189- raise HTTPException (
190- status_code = status .HTTP_400_BAD_REQUEST ,
191- detail = {
192- "error" : "Invalid query" ,
193- "messages" : query_errors ,
194- },
196+ raise ValidationException (
197+ message = "Invalid natural language query" ,
198+ validation_errors = [{"field" : "query" , "error" : e } for e in query_errors ],
195199 )
196200
197201 # Validate database ID (Phase 2.2: Security Implementation)
@@ -202,9 +206,9 @@ async def generate_sql(request: Request, query_request: QueryRequest) -> QueryRe
202206 error = db_error ,
203207 database_id = query_request .database_id ,
204208 )
205- raise HTTPException (
206- status_code = status . HTTP_400_BAD_REQUEST ,
207- detail = { " error" : db_error },
209+ raise ValidationException (
210+ message = db_error or "Invalid database ID" ,
211+ validation_errors = [{ "field" : "database_id" , " error" : db_error }] ,
208212 )
209213
210214 logger .info (
@@ -256,15 +260,21 @@ async def generate_sql(request: Request, query_request: QueryRequest) -> QueryRe
256260 warnings = result .warnings ,
257261 )
258262
263+ except ModelInferenceException :
264+ # Let custom exception handlers deal with this
265+ raise
266+ except SchemaNotFoundException :
267+ # Let custom exception handlers deal with this
268+ raise
259269 except Exception as e :
260270 logger .error (
261271 "generate_sql_error" ,
262272 error = str (e ),
263273 database_id = query_request .database_id ,
264274 )
265- raise HTTPException (
266- status_code = status . HTTP_500_INTERNAL_SERVER_ERROR ,
267- detail = {"error " : "SQL generation failed" , "message" : str ( e ) },
275+ raise ModelInferenceException (
276+ message = f"SQL generation failed: { str ( e ) } " ,
277+ details = {"database_id " : query_request . database_id },
268278 ) from e
269279
270280
@@ -292,9 +302,9 @@ async def validate_sql(
292302 error = db_error ,
293303 database_id = validation_request .database_id ,
294304 )
295- raise HTTPException (
296- status_code = status . HTTP_400_BAD_REQUEST ,
297- detail = { " error" : db_error },
305+ raise ValidationException (
306+ message = db_error or "Invalid database ID" ,
307+ validation_errors = [{ "field" : "database_id" , " error" : db_error }] ,
298308 )
299309
300310 logger .info (
@@ -364,9 +374,9 @@ async def get_schema(request: Request, database_id: str) -> SchemaResponse:
364374 error = db_error ,
365375 database_id = database_id ,
366376 )
367- raise HTTPException (
368- status_code = status . HTTP_400_BAD_REQUEST ,
369- detail = { " error" : db_error },
377+ raise ValidationException (
378+ message = db_error or "Invalid database ID" ,
379+ validation_errors = [{ "field" : "database_id" , " error" : db_error }] ,
370380 )
371381
372382 logger .info ("get_schema_request" , database_id = database_id )
@@ -418,9 +428,9 @@ async def register_schema(
418428 error = db_error ,
419429 database_id = schema_request .database_id ,
420430 )
421- raise HTTPException (
422- status_code = status . HTTP_400_BAD_REQUEST ,
423- detail = { " error" : db_error },
431+ raise ValidationException (
432+ message = db_error or "Invalid database ID" ,
433+ validation_errors = [{ "field" : "database_id" , " error" : db_error }] ,
424434 )
425435
426436 logger .info (
@@ -485,10 +495,7 @@ async def get_reasoning_trace(
485495 history = engine .get_query_history (query_id )
486496
487497 if history is None :
488- raise HTTPException (
489- status_code = status .HTTP_404_NOT_FOUND ,
490- detail = {"error" : "Query not found" , "query_id" : query_id },
491- )
498+ raise QueryNotFoundException (query_id = query_id )
492499
493500 # Convert reasoning trace to response model
494501 reasoning_trace = [
@@ -513,14 +520,12 @@ async def get_reasoning_trace(
513520 created_at = history .created_at ,
514521 )
515522
516- except HTTPException :
523+ except QueryNotFoundException :
517524 raise
518525 except Exception as e :
519526 logger .error ("get_reasoning_trace_error" , error = str (e ), query_id = query_id )
520- raise HTTPException (
521- status_code = status .HTTP_500_INTERNAL_SERVER_ERROR ,
522- detail = {"error" : "Failed to retrieve reasoning trace" , "message" : str (e )},
523- ) from e
527+ # Let global exception handler deal with unhandled exceptions
528+ raise
524529
525530
526531@router .post ("/agent/retry" , response_model = QueryResponse )
@@ -541,7 +546,6 @@ async def retry_query(request: Request, retry_request: RetryRequest) -> QueryRes
541546 )
542547
543548 from app .agent import get_agent_engine
544- from app .exceptions import QueryNotFoundException
545549
546550 try :
547551 engine = await get_agent_engine ()
@@ -580,25 +584,17 @@ async def retry_query(request: Request, retry_request: RetryRequest) -> QueryRes
580584 warnings = result .warnings ,
581585 )
582586
583- except QueryNotFoundException as e :
584- raise HTTPException (
585- status_code = status .HTTP_404_NOT_FOUND ,
586- detail = {
587- "error" : "Query not found" ,
588- "message" : str (e ),
589- "query_id" : retry_request .query_id ,
590- },
591- ) from e
587+ except QueryNotFoundException :
588+ # Let custom exception handler deal with this
589+ raise
592590 except Exception as e :
593591 logger .error (
594592 "retry_query_error" ,
595593 error = str (e ),
596594 query_id = retry_request .query_id ,
597595 )
598- raise HTTPException (
599- status_code = status .HTTP_500_INTERNAL_SERVER_ERROR ,
600- detail = {"error" : "Retry failed" , "message" : str (e )},
601- ) from e
596+ # Let global exception handler deal with unhandled exceptions
597+ raise
602598
603599
604600# =============================================================================
@@ -656,11 +652,7 @@ async def login(request: Request, credentials: LoginRequest) -> TokenResponse:
656652 )
657653
658654 logger .warning ("authentication_failed" , username = credentials .username )
659- raise HTTPException (
660- status_code = status .HTTP_401_UNAUTHORIZED ,
661- detail = "Incorrect username or password" ,
662- headers = {"WWW-Authenticate" : "Bearer" },
663- )
655+ raise AuthenticationException (message = "Incorrect username or password" )
664656
665657
666658# =============================================================================
0 commit comments