feat: add proper HTTP status codes to all API error responses

- 217 error returns across 18 route files + api.py now use JSONResponse
  with appropriate HTTP status codes instead of returning HTTP 200
- Status code distribution: 500 (121), 400 (39), 503 (28), 404 (24), 409 (3), 502 (2)
- Fixed language.py tuple-return bug (was serializing as JSON array)
- Fixed bare except clauses in bipolar_mode.py and voice.py
- Body-level error schemas preserved (status/error + success/error patterns)
  so web UI continues working without changes
- chat.py (SSE) unchanged: errors sent within stream protocol
- All 170 tests pass
This commit is contained in:
2026-04-15 15:43:18 +03:00
parent 33b2033cc3
commit edc9f27925
19 changed files with 243 additions and 227 deletions

View File

@@ -1,6 +1,7 @@
"""Figurine subscriber and send routes."""
from fastapi import APIRouter, Form
from fastapi.responses import JSONResponse
import globals
from utils.figurine_notifier import (
load_subscribers as figurine_load_subscribers,
@@ -29,7 +30,7 @@ async def add_figurine_subscriber(user_id: str = Form(...)):
ok = figurine_add_subscriber(uid)
return {"status": "ok", "added": ok}
except Exception as e:
return {"status": "error", "message": str(e)}
return JSONResponse(status_code=500, content={"status": "error", "message": str(e)})
@router.delete("/figurines/subscribers/{user_id}")
@@ -39,7 +40,7 @@ async def delete_figurine_subscriber(user_id: str):
ok = figurine_remove_subscriber(uid)
return {"status": "ok", "removed": ok}
except Exception as e:
return {"status": "error", "message": str(e)}
return JSONResponse(status_code=500, content={"status": "error", "message": str(e)})
@router.post("/figurines/send_now")
@@ -49,7 +50,7 @@ async def figurines_send_now(tweet_url: str = Form(None)):
logger.info(f"Sending figurine DMs to all subscribers, tweet_url: {tweet_url}")
globals.client.loop.create_task(send_figurine_dm_to_all_subscribers(globals.client, tweet_url=tweet_url))
return {"status": "ok", "message": "Figurine DMs queued"}
return {"status": "error", "message": "Bot not ready"}
return JSONResponse(status_code=503, content={"status": "error", "message": "Bot not ready"})
@router.post("/figurines/send_to_user")
@@ -59,14 +60,14 @@ async def figurines_send_to_user(user_id: str = Form(...), tweet_url: str = Form
if not globals.client or not globals.client.loop or not globals.client.loop.is_running():
logger.error("Bot not ready")
return {"status": "error", "message": "Bot not ready"}
return JSONResponse(status_code=503, content={"status": "error", "message": "Bot not ready"})
try:
user_id_int = int(user_id)
logger.debug(f"Parsed user_id as {user_id_int}")
except ValueError:
logger.error(f"Invalid user ID: '{user_id}'")
return {"status": "error", "message": "Invalid user ID"}
return JSONResponse(status_code=400, content={"status": "error", "message": "Invalid user ID"})
# Clean up tweet URL if it's empty string
if tweet_url == "":