Skip to content

Commit af5d8a5

Browse files
committed
fix: API error management
1 parent 479efd3 commit af5d8a5

File tree

1 file changed

+28
-32
lines changed

1 file changed

+28
-32
lines changed

app/main.py

Lines changed: 28 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -314,13 +314,13 @@ async def call_list_get(
314314
try:
315315
phone_number = PhoneNumber(phone_number) if phone_number else None
316316
except ValueError as e:
317-
raise _validation_error(e)
317+
raise RequestValidationError([f"Invalid phone number: {e}"]) from e
318318

319319
count = 100
320320
calls, _ = await _db.call_asearch_all(phone_number=phone_number, count=count)
321321
if not calls:
322-
raise _standard_error(
323-
message=f"Call {phone_number} not found",
322+
raise HTTPException(
323+
detail=f"Call {phone_number} not found",
324324
status_code=HTTPStatus.NOT_FOUND,
325325
)
326326

@@ -352,11 +352,11 @@ async def call_get(call_id_or_phone_number: str) -> CallGetModel:
352352
try:
353353
phone_number = PhoneNumber(call_id_or_phone_number)
354354
except ValueError as e:
355-
raise _validation_error(e)
355+
raise RequestValidationError([str(e)]) from e
356356
call = await _db.call_asearch_one(phone_number=phone_number)
357357
if not call:
358-
raise _standard_error(
359-
message=f"Call {phone_number} not found",
358+
raise HTTPException(
359+
detail=f"Call {call_id_or_phone_number} not found",
360360
status_code=HTTPStatus.NOT_FOUND,
361361
)
362362
return TypeAdapter(CallGetModel).dump_python(call)
@@ -379,7 +379,7 @@ async def call_post(request: Request) -> CallGetModel:
379379
body = await request.json()
380380
initiate = CallInitiateModel.model_validate(body)
381381
except ValidationError as e:
382-
raise _validation_error(e)
382+
raise RequestValidationError([str(e)]) from e
383383

384384
url, call = await _communicationservices_event_url(initiate.phone_number, initiate)
385385
span_attribute(CallAttributes.CALL_ID, str(call.call_id))
@@ -490,8 +490,8 @@ async def communicationservices_event_post(
490490
# Validate JWT token
491491
service_jwt: str | None = request.headers.get("Authorization")
492492
if not service_jwt:
493-
raise _standard_error(
494-
message="Authorization header missing",
493+
raise HTTPException(
494+
detail="Authorization header missing",
495495
status_code=HTTPStatus.UNAUTHORIZED,
496496
)
497497

@@ -511,24 +511,18 @@ async def communicationservices_event_post(
511511
)
512512
except jwt.PyJWTError:
513513
logger.warning("Invalid JWT token", exc_info=True)
514-
raise _standard_error(
515-
message="Invalid JWT token",
514+
raise HTTPException(
515+
detail="Invalid JWT token",
516516
status_code=HTTPStatus.UNAUTHORIZED,
517517
)
518518

519519
# Validate request
520520
try:
521521
events = await request.json()
522-
except ValueError:
523-
raise _standard_error(
524-
message="Invalid JSON format",
525-
status_code=HTTPStatus.BAD_REQUEST,
526-
)
522+
except ValueError as e:
523+
raise RequestValidationError([f"Invalid JSON format: {e}"]) from e
527524
if not events or not isinstance(events, list):
528-
raise _standard_error(
529-
message="Events must be a list",
530-
status_code=HTTPStatus.BAD_REQUEST,
531-
)
525+
raise RequestValidationError(["Events must be a list"])
532526

533527
# Process events in parallel
534528
await asyncio.gather(
@@ -820,11 +814,9 @@ async def _training_callback(_call: CallStateModel) -> None:
820814
training_callback=_training_callback,
821815
)
822816
if not event_status:
823-
return JSONResponse(
824-
content=_standard_error(
825-
message="SMS event failed",
826-
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
827-
)
817+
raise HTTPException(
818+
detail="SMS event failed",
819+
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
828820
)
829821

830822
return Response(
@@ -835,7 +827,9 @@ async def _training_callback(_call: CallStateModel) -> None:
835827

836828

837829
@api.exception_handler(StarletteHTTPException)
838-
async def http_exception_handler(request: Request, exc: StarletteHTTPException): # noqa: ARG001
830+
async def http_exception_handler(
831+
request: Request, exc: StarletteHTTPException
832+
) -> JSONResponse: # noqa: ARG001
839833
"""
840834
Handle HTTP exceptions and return the error in a standard format.
841835
"""
@@ -846,7 +840,9 @@ async def http_exception_handler(request: Request, exc: StarletteHTTPException):
846840

847841

848842
@api.exception_handler(RequestValidationError)
849-
async def validation_exception_handler(request: Request, exc: RequestValidationError): # noqa: ARG001
843+
async def validation_exception_handler(
844+
request: Request, exc: RequestValidationError
845+
) -> JSONResponse: # noqa: ARG001
850846
"""
851847
Handle validation exceptions and return the error in a standard format.
852848
"""
@@ -876,7 +872,7 @@ def _str_to_contexts(value: str | None) -> set[CallContextEnum] | None:
876872
return res or None
877873

878874

879-
def _validation_error(e: ValidationError | Exception) -> HTTPException:
875+
def _validation_error(e: ValidationError | Exception) -> JSONResponse:
880876
"""
881877
Generate a standard validation error response.
882878
"""
@@ -896,9 +892,9 @@ def _validation_error(e: ValidationError | Exception) -> HTTPException:
896892

897893
def _standard_error(
898894
message: str,
895+
status_code,
899896
details: list[str] | None = None,
900-
status_code: HTTPStatus = HTTPStatus.BAD_REQUEST,
901-
) -> HTTPException:
897+
) -> JSONResponse:
902898
"""
903899
Generate a standard error response.
904900
"""
@@ -908,8 +904,8 @@ def _standard_error(
908904
message=message,
909905
)
910906
)
911-
return HTTPException(
912-
detail=model.model_dump_json(),
907+
return JSONResponse(
908+
content=model.model_dump(mode="json"),
913909
status_code=status_code,
914910
)
915911

0 commit comments

Comments
 (0)