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

@@ -2,6 +2,7 @@
import asyncio
from fastapi import APIRouter
from fastapi.responses import JSONResponse
import globals
from routes.models import BipolarTriggerRequest
from utils.logger import get_logger
@@ -106,23 +107,23 @@ def trigger_argument(data: BipolarTriggerRequest):
try:
channel_id = int(data.channel_id)
except ValueError:
return {"status": "error", "message": "Invalid channel ID format"}
return JSONResponse(status_code=400, content={"status": "error", "message": "Invalid channel ID format"})
message_id = None
if data.message_id:
try:
message_id = int(data.message_id)
except ValueError:
return {"status": "error", "message": "Invalid message ID format"}
return JSONResponse(status_code=400, content={"status": "error", "message": "Invalid message ID format"})
if not is_bipolar_mode():
return {"status": "error", "message": "Bipolar mode is not enabled"}
return JSONResponse(status_code=400, content={"status": "error", "message": "Bipolar mode is not enabled"})
if is_argument_in_progress(channel_id):
return {"status": "error", "message": "An argument is already in progress in this channel"}
return JSONResponse(status_code=409, content={"status": "error", "message": "An argument is already in progress in this channel"})
if not globals.client or not globals.client.loop or not globals.client.loop.is_running():
return {"status": "error", "message": "Discord client not ready"}
return JSONResponse(status_code=503, content={"status": "error", "message": "Discord client not ready"})
# If message_id is provided, use the message-based trigger
if message_id:
@@ -145,7 +146,7 @@ def trigger_argument(data: BipolarTriggerRequest):
# Otherwise, find the channel and trigger normally
channel = globals.client.get_channel(channel_id)
if not channel:
return {"status": "error", "message": f"Channel {channel_id} not found"}
return JSONResponse(status_code=404, content={"status": "error", "message": f"Channel {channel_id} not found"})
# Trigger the argument
globals.client.loop.create_task(force_trigger_argument(channel, globals.client, data.context))
@@ -168,19 +169,19 @@ def trigger_dialogue(data: dict):
message_id_str = data.get("message_id")
if not message_id_str:
return {"status": "error", "message": "Message ID is required"}
return JSONResponse(status_code=400, content={"status": "error", "message": "Message ID is required"})
# Parse message ID
try:
message_id = int(message_id_str)
except ValueError:
return {"status": "error", "message": "Invalid message ID format"}
return JSONResponse(status_code=400, content={"status": "error", "message": "Invalid message ID format"})
if not is_bipolar_mode():
return {"status": "error", "message": "Bipolar mode is not enabled"}
return JSONResponse(status_code=400, content={"status": "error", "message": "Bipolar mode is not enabled"})
if not globals.client or not globals.client.loop or not globals.client.loop.is_running():
return {"status": "error", "message": "Discord client not ready"}
return JSONResponse(status_code=503, content={"status": "error", "message": "Discord client not ready"})
async def trigger_dialogue_task():
try:
@@ -191,7 +192,7 @@ def trigger_dialogue(data: dict):
try:
message = await channel.fetch_message(message_id)
break
except:
except Exception:
continue
if not message:
@@ -272,7 +273,7 @@ def cleanup_bipolar_webhooks():
from utils.bipolar_mode import cleanup_webhooks
if not globals.client or not globals.client.loop or not globals.client.loop.is_running():
return {"status": "error", "message": "Discord client not ready"}
return JSONResponse(status_code=503, content={"status": "error", "message": "Discord client not ready"})
globals.client.loop.create_task(cleanup_webhooks(globals.client))
return {"status": "ok", "message": "Webhook cleanup started"}