Sub-dependencies
You can create dependencies that have sub-dependencies.
They can be as "deep" as you need them to be.
FastAPI will take care of solving them.
First dependency "dependable"
You could create a first dependency ("dependable") like:
from fastapi import Cookie, Depends, FastAPI app = FastAPI() def query_extractor(q: str = None): return q def query_or_cookie_extractor( q: str = Depends(query_extractor), last_query: str = Cookie(None) ): if not q: return last_query return q @app.get("/items/") async def read_query(query_or_default: str = Depends(query_or_cookie_extractor)): return {"q_or_cookie": query_or_default}
It declares an optional query parameter q
as a str
, and then it just returns it.
This is quite simple (not very useful), but will help us focus on how the sub-dependencies work.
Second dependency, "dependable" and "dependant"
Then you can create another dependency function (a "dependable") that at the same time declares a dependency of its own (so it is a "dependant" too):
from fastapi import Cookie, Depends, FastAPI app = FastAPI() def query_extractor(q: str = None): return q def query_or_cookie_extractor( q: str = Depends(query_extractor), last_query: str = Cookie(None) ): if not q: return last_query return q @app.get("/items/") async def read_query(query_or_default: str = Depends(query_or_cookie_extractor)): return {"q_or_cookie": query_or_default}
Let's focus on the parameters declared:
- Even though this function is a dependency ("dependable") itself, it also declares another dependency (it "depends" on something else).
- It depends on the
query_extractor
, and assigns the value returned by it to the parameterq
.
- It depends on the
- It also declares an optional
last_query
cookie, as astr
.- Let's imagine that if the user didn't provide any query
q
, we just use the last query used, that we had saved to a cookie before.
- Let's imagine that if the user didn't provide any query
Use the dependency
Then we can use the dependency with:
from fastapi import Cookie, Depends, FastAPI app = FastAPI() def query_extractor(q: str = None): return q def query_or_cookie_extractor( q: str = Depends(query_extractor), last_query: str = Cookie(None) ): if not q: return last_query return q @app.get("/items/") async def read_query(query_or_default: str = Depends(query_or_cookie_extractor)): return {"q_or_cookie": query_or_default}
Info
Notice that we are only declaring one dependency in the path operation function, the query_or_cookie_extractor
.
But FastAPI will know that it has to solve query_extractor
first, to pass the results of that to query_or_cookie_extractor
while calling it.
Recap
Apart from all the fancy words used here, the Dependency Injection system is quite simple.
Just functions that look the same as the path operation functions.
But still, it is very powerful, and allows you to declare arbitrarily deeply nested dependency "graphs" (trees).
Tip
All this might not seem as useful with these simple examples.
But you will see how useful it is in the chapters about security.
And you will also see the amounts of code it will save you.