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, Form
from fastapi.responses import JSONResponse
import discord
import globals
from utils.dm_logger import dm_logger
@@ -29,7 +30,7 @@ async def initiate_voice_call(user_id: str = Form(...), voice_channel_id: str =
# Check if bot is running
if not globals.client or not globals.client.loop or not globals.client.loop.is_running():
return {"success": False, "error": "Bot is not running"}
return JSONResponse(status_code=503, content={"success": False, "error": "Bot is not running"})
# Run the voice call setup in the bot's event loop
try:
@@ -41,7 +42,7 @@ async def initiate_voice_call(user_id: str = Form(...), voice_channel_id: str =
return result
except Exception as e:
logger.error(f"Error initiating voice call: {e}", exc_info=True)
return {"success": False, "error": str(e)}
return JSONResponse(status_code=500, content={"success": False, "error": str(e)})
async def _initiate_voice_call_impl(user_id: str, voice_channel_id: str):
@@ -57,11 +58,11 @@ async def _initiate_voice_call_impl(user_id: str, voice_channel_id: str):
# Get user and channel
user = await globals.client.fetch_user(user_id_int)
if not user:
return {"success": False, "error": "User not found"}
return JSONResponse(status_code=404, content={"success": False, "error": "User not found"})
channel = globals.client.get_channel(channel_id_int)
if not channel or not isinstance(channel, discord.VoiceChannel):
return {"success": False, "error": "Voice channel not found"}
return JSONResponse(status_code=404, content={"success": False, "error": "Voice channel not found"})
# Get a text channel for voice operations (use first text channel in guild)
text_channel = None
@@ -71,14 +72,14 @@ async def _initiate_voice_call_impl(user_id: str, voice_channel_id: str):
break
if not text_channel:
return {"success": False, "error": "No accessible text channel found"}
return JSONResponse(status_code=404, content={"success": False, "error": "No accessible text channel found"})
# Start containers
logger.info("Starting voice containers...")
containers_started = await ContainerManager.start_voice_containers()
if not containers_started:
return {"success": False, "error": "Failed to start voice containers"}
return JSONResponse(status_code=500, content={"success": False, "error": "Failed to start voice containers"})
# Start voice session
logger.info(f"Starting voice session in {channel.name}")
@@ -88,7 +89,7 @@ async def _initiate_voice_call_impl(user_id: str, voice_channel_id: str):
await session_manager.start_session(channel.guild.id, channel, text_channel)
except Exception as e:
await ContainerManager.stop_voice_containers()
return {"success": False, "error": f"Failed to start voice session: {str(e)}"}
return JSONResponse(status_code=500, content={"success": False, "error": f"Failed to start voice session: {str(e)}"})
# Set up voice call tracking (use integer ID)
session_manager.active_session.call_user_id = user_id_int
@@ -143,7 +144,7 @@ Keep it brief (1-2 sentences). Make it feel personal and enthusiastic!"""
except Exception as e:
logger.error(f"Error in voice call implementation: {e}", exc_info=True)
return {"success": False, "error": str(e)}
return JSONResponse(status_code=500, content={"success": False, "error": str(e)})
async def _voice_call_timeout_handler(voice_session, user: discord.User, channel: discord.VoiceChannel):
@@ -171,7 +172,7 @@ async def _voice_call_timeout_handler(voice_session, user: discord.User, channel
# Log to DM logger
dm_logger.log_user_message(user, sent_message, is_bot_message=True)
except:
except Exception:
pass
except asyncio.CancelledError: