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

@@ -3,6 +3,7 @@
import io
from typing import List
from fastapi import APIRouter, UploadFile, File, Form
from fastapi.responses import JSONResponse
import discord
import globals
from utils.logger import get_logger
@@ -23,7 +24,7 @@ async def manual_send(
try:
channel = globals.client.get_channel(int(channel_id))
if not channel:
return {"status": "error", "message": "Channel not found"}
return JSONResponse(status_code=404, content={"status": "error", "message": "Channel not found"})
# Read file content immediately before the request closes
file_data = []
@@ -36,7 +37,7 @@ async def manual_send(
})
except Exception as e:
logger.error(f"Failed to read file {file.filename}: {e}")
return {"status": "error", "message": f"Failed to read file {file.filename}: {e}"}
return JSONResponse(status_code=500, content={"status": "error", "message": f"Failed to read file {file.filename}: {e}"})
async def send_message_and_files():
try:
@@ -70,7 +71,7 @@ async def manual_send(
return {"status": "ok", "message": "Message and files queued for sending"}
except Exception as e:
return {"status": "error", "message": f"Error: {e}"}
return JSONResponse(status_code=500, content={"status": "error", "message": f"Error: {e}"})
@router.post("/manual/send-webhook")
@@ -88,10 +89,10 @@ async def manual_send_webhook(
channel = globals.client.get_channel(int(channel_id))
if not channel:
return {"status": "error", "message": "Channel not found"}
return JSONResponse(status_code=404, content={"status": "error", "message": "Channel not found"})
if persona not in ["miku", "evil"]:
return {"status": "error", "message": "Invalid persona. Must be 'miku' or 'evil'"}
return JSONResponse(status_code=400, content={"status": "error", "message": "Invalid persona. Must be 'miku' or 'evil'"})
file_data = []
for file in files:
@@ -103,7 +104,7 @@ async def manual_send_webhook(
})
except Exception as e:
logger.error(f"Failed to read file {file.filename}: {e}")
return {"status": "error", "message": f"Failed to read file {file.filename}: {e}"}
return JSONResponse(status_code=500, content={"status": "error", "message": f"Failed to read file {file.filename}: {e}"})
async def send_webhook_message():
try:
@@ -146,7 +147,7 @@ async def manual_send_webhook(
return {"status": "ok", "message": f"Webhook message queued for sending as {persona}"}
except Exception as e:
return {"status": "error", "message": f"Error: {e}"}
return JSONResponse(status_code=500, content={"status": "error", "message": f"Error: {e}"})
@router.post("/messages/react")
@@ -158,17 +159,17 @@ async def add_reaction_to_message(
"""Add a reaction to a specific message"""
try:
if not globals.client or not globals.client.loop or not globals.client.loop.is_running():
return {"status": "error", "message": "Bot not ready"}
return JSONResponse(status_code=503, content={"status": "error", "message": "Bot not ready"})
try:
msg_id = int(message_id)
chan_id = int(channel_id)
except ValueError:
return {"status": "error", "message": "Invalid message ID or channel ID format"}
return JSONResponse(status_code=400, content={"status": "error", "message": "Invalid message ID or channel ID format"})
channel = globals.client.get_channel(chan_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"})
async def add_reaction_task():
try:
@@ -193,4 +194,4 @@ async def add_reaction_to_message(
except Exception as e:
logger.error(f"Failed to add reaction: {e}")
return {"status": "error", "message": f"Failed to add reaction: {e}"}
return JSONResponse(status_code=500, content={"status": "error", "message": f"Failed to add reaction: {e}"})