4.7 KiB
Plan 2 — Error Handling & Code Quality
Items covered: #5 (magic return types), #6 (silent error suppression), #15 (hardcoded CORS warning)
Context
You are working on a FastAPI backend for a baby monitor / sleep tracker app. The codebase lives under app/. This plan improves how errors are communicated — both internally between modules and externally to API clients. Make one change at a time, re-read each modified file before moving to the next, and run the tests at the end.
Tasks
1. Replace magic return types with typed exceptions (app/crud.py and app/routers/sessions.py)
Step 1 — Read the files first
Read app/crud.py (specifically the session-end function around lines 57-82) and app/routers/sessions.py (specifically the caller around lines 64-73) before touching anything. Understand the full flow.
Step 2 — Define typed exceptions
Create a new file app/exceptions.py with the following exceptions:
class SessionNotFoundError(Exception):
pass
class SessionAlreadyEndedError(Exception):
pass
class InvalidEndTimeError(Exception):
pass
Step 3 — Update crud.py
In the session-end function in app/crud.py, replace each magic return value with the appropriate raise:
- Where it currently
return None(session not found) →raise SessionNotFoundError - Where it currently
return False(session already ended) →raise SessionAlreadyEndedError - Where it currently
return "invalid"→raise InvalidEndTimeError
Change the function's return type annotation to SleepSession (it now only returns on success).
Import the exceptions at the top of crud.py:
from app.exceptions import SessionNotFoundError, SessionAlreadyEndedError, InvalidEndTimeError
Step 4 — Update sessions.py
In app/routers/sessions.py, replace the chain of if result is None / if result is False / if result == "invalid" checks with try/except blocks that catch each exception and map it to the correct HTTPException:
SessionNotFoundError→HTTPException(status_code=404, detail="Session not found")SessionAlreadyEndedError→HTTPException(status_code=409, detail="Session already ended")InvalidEndTimeError→HTTPException(status_code=422, detail="End time is invalid")
Import the exceptions at the top of sessions.py.
2. Replace silent error suppression with 422 responses (app/routers/stats.py)
Step 1 — Read the file first
Read app/routers/stats.py and locate both silent-suppression patterns (around lines 24-25 and 114-115). They look like:
try:
day_start_time = time.fromisoformat(day_start)
except ValueError:
return {"days": []} # silent empty response
Step 2 — Replace each one
Replace every such except ValueError: return {...} block with:
except ValueError:
raise HTTPException(
status_code=422,
detail=f"Invalid format: {day_start!r}"
)
Adjust the detail message to name the specific parameter that was malformed. Make sure HTTPException is imported from fastapi at the top of the file.
3. Add a CORS misconfiguration warning (app/config.py and app/main.py)
Step 1 — Read both files first
Read app/config.py to understand the Settings model and how CORS_ORIGINS is defined. Read app/main.py to see where settings is used.
Step 2 — Add a startup warning
In app/main.py, add a startup event (or inline check at module load time) that logs a warning if CORS_ORIGINS still has the localhost default value. Example:
import logging
logger = logging.getLogger(__name__)
@app.on_event("startup")
async def warn_if_default_cors():
if "localhost" in settings.CORS_ORIGINS:
logger.warning(
"CORS_ORIGINS contains localhost (%s). "
"Set the CORS_ORIGINS environment variable in production.",
settings.CORS_ORIGINS,
)
If a startup event already exists, add the check inside it rather than creating a duplicate.
Also add a comment directly above the CORS_ORIGINS field in app/config.py:
# Override in production via the CORS_ORIGINS environment variable.
# Leaving this as localhost will cause CORS errors in deployed environments.
CORS_ORIGINS: str = "http://localhost:5173"
Verification
Run the full test suite after all changes:
pytest
All existing tests must pass. If any test fails because it was checking for the old magic-return behaviour (e.g. asserting result == "invalid"), update those tests to expect the correct HTTPException status code instead. Do not suppress or skip failing tests. Do not move on to Plan 3 until the test suite is green.