Reputation: 43
I develop with FastApi, and want to contain traceback info in response when error occur;
To do so, I define exception handlers in exception_handler.py
:
from fastapi.responses import JSONResponse
from fastapi import status
from fastapi import FastAPI, Request
from traceback import format_exc, print_exc
def general_exception_handler(req: Request, exc: Exception):
'''
Exception handler for unspecified exceptions
'''
tracback_msg = format_exc()
return JSONResponse(
{
"code": status.HTTP_500_INTERNAL_SERVER_ERROR,
"message": f"error info: {tracback_msg}",
# "message": f"error info: {str(exc)}",
"data": "",
},
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
)
And attach those handler to fastappi app instance in server.py
:
server.py
is where I create app instance and attach extra function to it like middlewares or exception handlers.
from core import router # api routers are defined in router.py
from fastapi import FastAPI
from core.exception_handler import general_exception_handler
app = FastAPI(
debug=False,
docs_url=None,
redoc_url=None
)
# attach exception handler to app instance
app.add_exception_handler(Exception, general_exception_handler)
# include routers to app intance
app.include_router(router.router)
The problem is, when exception was raised, traceback message return by format_exc()
is None
;
But when I used str(exc)
like the annotated code, I got the exception info properly but of course without traceback info.
Upvotes: 2
Views: 2113
Reputation: 11
There's always format_exception, which takes an explicit exception argument, rather than grabbing the current one from sys.exc_info()
.
Upvotes: 0
Reputation: 311
It will not work because the exception handler receives the exception as parameter instead of catching the exception itself, meaning that there is no stacktrace in this case.
If you want to have the stacktrace, you should create a middleware or a custom API router that will actually capture the exception and return the message the way you want. I usually prefer to use a custom API Route instead of using middleware because it is more explicit and gives you more flexibility.
You can write something like this
class MyRoute(APIRoute):
def get_route_handler(self) -> Callable:
original_route_handler = super().get_route_handler()
async def custom_route_handler(request: Request) -> Response:
try:
return await original_route_handler(request)
except Exception as exc:
tracback_msg = format_exc()
# your return goes here
return custom_route_handler
Then you override the default route handler from fastapi
app = FastAPI()
app.router.route_class = MyRoute
It should give you want you want
Upvotes: 3