[FEATURE] Contextmanager as dependency
See original GitHub issueDepends()
works great, but does not support post-response cleanup. How about injecting from context managers? Taking the SQL Db example, it would not need middleware anymore:
from contextlib import contextmanager
@contextmanager
def db() -> Session:
db_session = Session()
try:
yield db_session
finally:
db_session.close()
@app.get("/users/{user_id}")
def read_user(user_id: int, db_session: Session = Depends(db)):
user = get_user(db_session, user_id=user_id)
return user
Middlewares do the job and they have been there forever, but from the FastAPI idiomatic approach request.scope
looks a bit of a “dumpster” - it’s not known in advance what to expect there without examining middlware docs/code. Middlewares also need to take care not to step on each other. And finally, not all paths may need that request.scope.db
. By supporting contextmanager injection, I believe code can be more idiomatic, and more efficient (e.g. because we’ll only initialize Session()
for requests that need it).
What do you think?
Implementation wise, I guess dependencies.utils.solve_dependencies
needs to return ctxmgrs
in addition to values
and errors
. Then during execution we can use either contextlib.ExitStack
or contextlib.AsyncExitStack
(the latter is Python 3.7 only though) to wrap the execution with.
Also, since a “thing” passed to Depends()
can be both callable and context manager, may be it worth having new DependsContextMgr()
class. And finally, I think there should be some type checking to make sure that only async context managers are injected into async request handlers and vise-versa.
I can work on a PR for this if the initiative is going to be accepted.
Issue Analytics
- State:
- Created 5 years ago
- Comments:10 (9 by maintainers)
I created a pull request that gets at this from a slightly different angle (#570). It supports functions similar to contextmanager-decorated functions or pytest yield fixtures. These can be easily used with enter and exit (and the async equivalents) by yielding inside the with statement.
I’m still working on docs for the pull request but I’ll include examples along the lines described above.
Implemented in version 0.42.0 https://github.com/tiangolo/fastapi/pull/595 Docs: https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-with-yield/
Thank you guys. It looks awesome!