Debugging FastAPI routes with pdb
When investigating an exception in a FastAPI route, sometimes it's just fine to add print statements and re-run a request. But for trickier situations, a debugger can be invaluable.
Flask's debug mode includes a full in-browser debugger, allowing you to inspect variables and interactively debug issues.
FastAPI's debug=True
mode looks similar, but only displays a non-interactive traceback in the browser. I find this a lot less useful, though an improvement on the non-debug 'Internal Server Error' message.
Fortunately, we can get an interactive debugger on exception with a tiny middleware:
from fastapi import FastAPI, Request
from starlette.middleware.base import BaseHTTPMiddleware
import traceback
app = FastAPI()
async def attach_debugger_on_exception(request: Request, call_next):
try:
response = await call_next(request)
except Exception:
traceback.print_exc()
# `set_trace` would create a breakpoint but the stack would stop here.
# `post_mortem` sets the relevant context to be where the exception happened.
import pdb
pdb.post_mortem()
raise
return response
if settings.DEBUG_BREAK_ON_EXCEPTION:
# Add last to run first and catch exceptions in other middlewares.
app.add_middleware(BaseHTTPMiddleware, dispatch=attach_debugger_on_exception)
Assuming your settings are configured using environment variables, it can be run with:
DEBUG_BREAK_ON_EXCEPTION=true uvicorn app.web.main:app --reload
Now, when an exception occurs, the browser will hang while your terminal drops into a pdb session. You can inspect variables, step through code, and figure out exactly what went wrong.
The FastAPI docs have a page on using your IDE to debug you app, but it is difficult to get the debugger to break on an api route exception since these are handled by Starlette to return an error response.
I personally prefer the console-based debugger anyway. It may not seem as friendly as an IDE at first, but with practice it becomes very effective and works in more scenarios.
As with any debugging tool, you probably want to validate your settings so that it does not inadvertently end up enabled in production.
Happy debugging!