Here's a self-contained minimal, reproducible, example with my use case:
from fastapi import FastAPI, Depends
app = FastAPI()
def dependency(request: Request, check: bool = True):
pass
@app.get("/1")
def read_root(t = Depends(dependency, check=False)):
return {"Hello": "World"}
@app.get("/2")
def read_root(t = Depends(dependency)):
return {"Hello": "World"}
I searched the docs and didn't find any reference of this being possible. Could this be done somehow with FastAPI today? Am I missing something?
If it is not possible today, how can this be implemented, I would gladly help with it.
Thanks!
I guess what you want is to pass additional parameters to dependencies when it's being referenced by the operations, rather than passing additional "dependencies". See https://fastapi.tiangolo.com/advanced/advanced-dependencies/
What do you mean by additional "dependencies"? What I want is exactly what you said:
what you want is to pass additional parameters to dependencies
Perhaps I wasn't clear enough.
I think boolean is not a good example for a parameters as I could create two versions of the same class to "parameterize" the dependency, as the docs say.
But imagine if the extra parameter is a dictionary key, this wouldn't be possible.
That's how Depends constructor looks:
class Depends:
def __init__(self, dependency: Callable = None, *, use_cache: bool = True):
So you can't pass kwargs here, but there is workaround (but I can't be sure about how good it will be working):
from fastapi import FastAPI, Depends, Request
app = FastAPI()
def dependency_factory(check: bool = True):
def dependency(request: Request):
if check:
return 1
return 2
return dependency
@app.get("/test_overrided")
def read_root(t=Depends(dependency_factory(check=False))):
return {"Hello": t}
@app.get("/test_default")
def read_root(t=Depends(dependency_factory())):
return {"Hello": t}
Yeah, I looked through this part of the code also... just wasn't sure if I was missing something.
I had this idea also! But it just wasn't pretty :smile:
Was wondering if this is a common use case or just me, because if it is common enough I might take some time to open a PR for this!
If you look better there is same idea here. I ain't looked here properly before my comment
class FixedContentQueryChecker:
def __init__(self, fixed_content: str):
self.fixed_content = fixed_content
def __call__(self, q: str = ""):
if q:
return self.fixed_content in q
return False
__init__ here works like outer def in my example and __call__ works like inner def. But class as dependency can be overkill imo if you need not lot of states or extended functionality. Just for passing flag i think factory is much more simple. I think I can extend docs with factory if it needed
@Kludex @tiangolo what do you think?
In the case of a boolean parameter, sure, classes might me a good solution. But for my case, being a dictionary key (actually a State key), the factory is a better fit, not better than passing it as a **kwargs to Depends, but better than classes!
There is no difference between class and factory, in case of classes you not bound with boolean either
I'm not saying that I would be bounded to boolean. But in the case of classes, I would need to create n instances, being n the number of dictionary keys I need, for example. While in the factory method that is not the case.
Ye, you can make it this way:
class QueryChecker:
def __init__(self, check: str = ""):
self.check= check
def __call__(self):
if check:
return check
return "default_value"
@app.get("/test_overrided")
def read_root(t=Depends(QueryChecker(check="foo"))):
return {"Hello": t}
@app.get("/test_default")
def read_root(t=Depends(QueryChecker())):
return {"Hello": t}
I had this idea also! But it just wasn't pretty smile
@victoraugustolls Why? haha
@Kludex @tiangolo what do you think?
It makes me feel important hahaha But I'm just a FastAPI lover :heart_eyes:
My opinion: I think there's space here (page that @phy25 recommended) to add a note with an alternative example, but without making too much noise about it. It's an alternative, it's nice to know, but it's not really necessary.
btw, I do use this alternative :)
Yeah... but creating a new instance of a class, depending of what it does, for each one of your endpoints, seems like a bad thing and unnecessary resource usage, at least I think. This is what I ended up doing:
def _get_service(key: str) -> HTTPService:
def _service(request: Request):
try:
return request.app.state.__getattr__(key)
except AttributeError:
service = HTTPService.factory(key)
request.app.state.__setattr__(
key=key,
value=service,
)
return service
return Depends(_service)
@lru_cache
def get_service(service: t.Type[HTTPService]) -> HTTPService:
return _get_service(key=service.__name__)
I don't think I need the @lru_cache as python default parameters are only evaluated once, but if I need to call get_service outside of a endpoint definition, and I know the service has been cached, it would work.
Just don't know if I should put a Lock around it :thinking:
My opinion: I think there's space here (page that @phy25 recommended) to add a note with an alternative example, but without making too much noise about it. It's an alternative, it's nice to know, but it's not really necessary.
Totally agree that a note about using a factory for your dependencies would be great!
@victoraugustolls Why? haha
@Kludex I really don't know hahah, just wasn't feeling it at the moment, something felt off. But it is the best solution so far!
Thanks for everyone that commented here! Going to close this off now!
Thanks for the help here everyone! :clap: :bow:
Thanks for reporting back and closing the issue :+1:
And yeah, if anyone wants to add a small alternative with factory functions to the docs that would be great too. :nerd_face: