-
-
Notifications
You must be signed in to change notification settings - Fork 8.6k
Description
Hello,
what I try to achieve is to rollback a database session on an unhanded exception and customize the response in that case.
The first one can be done, handling the database connection in its own method with a try, except, finally block and use it as a dependency. The second one can be done using a custom route class.
But combining both will not work as I wish, because the dependency would be executed after leaving the custom route class.
I've found similar issues/questions about this, but no satisfying answer.
Here's my minimal example which of course doesn't work as a like to have. (Of course the get_db() method returns a database session in real life)
What must I change or how does the pattern must look like to reach out what I want?
#!usr/bin/env python
# -*- coding: utf-8 -*-
import logging
from typing import Callable
import uvicorn
from fastapi import Depends, FastAPI, Request, Response
from fastapi.exceptions import HTTPException
from fastapi.routing import APIRoute
logging.basicConfig(level=logging.DEBUG)
class ExceptionRouter(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:
logging.exception("Unexpected error")
body = await request.body()
detail = {"errors": str(exc), "body": body.decode()}
raise HTTPException(status_code=500, detail=detail)
return custom_route_handler
def get_db() -> str:
db = "mydb"
try:
yield db
except Exception:
logging.debug("rolling back db")
raise
finally:
logging.debug("closing db")
app = FastAPI()
app.router.route_class = ExceptionRouter
@app.get("/exception",)
async def raise_exception(db: str = Depends(get_db)):
raise Exception("Unexpected error!")
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)fin swimmer