question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[FEATURE] Dependency decorator

See original GitHub issue

Is your feature request related to a problem? Please describe. I’ve got dependency methods relying on other dependencies, not a routing/path level, where I don’t need the return values. Look at the difference of the produce_kitten dependency before and after.

def often_true(is_true: bool):
    if not is_true:
        raise HTTPException(status_code=401)

def produce_kitten(possibly_true: NoReturn = Depends(often_true)):
    # only produce kittens if often_true has not raised
    pass

@app.get('/', dependencies=[Depends(do_something_interesting)])
def hello():
    return {'Hello': 'World'}

Describe the solution you’d like If we’d be able to use dependencies in decorators for non-path/routing methods it would be more readable and concise IMO.

def often_true(is_true: bool):
    if not is_true:
        raise HTTPException(status_code=401)

@depends(dependencies=[Depends(often_true)])
def produce_kitten():
    # only produce kittens if often_true has not raised
    pass

@app.get('/', dependencies=[Depends(do_something_interesting)])
def hello():
    return {'Hello': 'World'}

Describe alternatives you’ve considered People have suggested putting similar things in the router dependency level and just doing more routes in https://github.com/tiangolo/fastapi/issues/688, but then it seems better to just calling the lower subdependencies directly from where they’re needed and avoid tainting the service contract.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:2
  • Comments:8 (5 by maintainers)

github_iconTop GitHub Comments

2reactions
lowercase00commented, Sep 11, 2020

Well, I know this is an old closed thread, and I definitely don’t have a compelling example, but just stopping by to give my 2c as a beginner that was a bit confused reading the documentation 😃 I really like something similar to what @MrMrRobat said. But also 100% agree with @dmontagu that readability is a personal preference.

I find this pretty clean and easy to use

@depends(my_dependency)
def produce_kitten(arg: None) -> None:
     # Ok, the function depends on something
     pass

This is a bit confusing to me, I find the logic harder to understand

def produce_kitten(arg: None = Depends(my_dependency)) -> None:
    # The default value of the argument of the function has a function called Depends, that takes my_dependency
    pass

This makes total sense, pretty comfortable to use since I’ve seen a lot of @login_required or @auth_required or @cross_origin() in Flask

@depends(admin_role)
@app.get('/')
def hello():
    # This is ok, easy to read, very common for django/flask
    pass 

This is pretty nice, similar to flask methods, very clean

@app.get('/', dependencies=[admin_role]) 
def login():
    # this is pretty nice, is cool that you don't have to stack decorators
    pass 
@app.get('/')
def login(user_data: UserFormData = Depends(admin_role)):
    # User data of schema xyz has a function as default value that depends on
    pass

My current use case is an ACL implementation. I’ve seen the fastapi_utils from @dmontagu which is great, and @cbv implementation that puts dependencies as class attributes is pretty nice really makes routes lighter, but still would prefer using cleaner decorators. Maybe someone comes up with a more convincing use case.

@henriklindgren and @MrMrRobat have you had the chance to implement something similar? I might be going that way to implement ACL.

1reaction
dmontagucommented, Nov 19, 2019

Not to say that this is a bad feature necessarily, but I personally don’t find this example very compelling.

If we’d be able to use dependencies in decorators for non-path/routing methods it would be more readable and concise IMO.

The version with @depends is actually longer than it would take to implement this using the existing system:

def produce_kitten(_: None = Depends(often_true)) -> None:
    # only produce kittens if often_true has not raised
    pass

(also, note: NoReturn is actually the wrong type hint here; that should only be used as a return type annotation, since no value can ever be of type NoReturn, and even then should only be used when the function always raises an exception, but in this case it can return None. And that’s what that argument’s value would be if the produce_kitten function were actually called by FastAPI.)

Also, in this specific case, you can easily eliminate the often_true dependency entirely:

def produce_kitten(is_true: bool):
    # only produce kittens if often_true has not raised
    if not is_true:
        raise HTTPException(status_code=401)

So I’m not (yet) convinced that an extra depends decorator would make things more readable or more concise.

For this case, I think it is at best a personal opinion that it is more readable, but I would argue that the best solution is to actually just change the pattern entirely. I worry that having this decorator would lead people to make more use of this semi-awkward pattern of having unused dependencies.


I recognize you may have a more complex example where this way of breaking apart the dependencies makes sense, but I think dependencies having other unused-argument dependencies is an anti-pattern more often than not, and is better handled through a function call inside a dependency and/or route, rather than being injected into another dependency via dependency injection.


Tweaks to the dependency injection system add a substantial amount of testing and documentation maintenance burden, and also add yet another thing a newcomer to a FastAPI codebase has to learn about. So I think this feature should meet a relatively high bar of usefulness in order to deserve implementation. I personally am not yet convinced this meets that bar, but a more compelling (set of) example(s) could definitely change my mind.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Dependency Injection using Decorators | by Chidume Nnamdi
This code is similiar to Injectable in Angular. The Injectable is a Decorator Factory. Know this, a Decorator Factory is a function that...
Read more >
Dependencies in path operation decorators - FastAPI
The path operation decorator receives an optional argument dependencies . ... These dependencies will be executed/solved the same way normal dependencies. But ...
Read more >
Angular & Dependency Injection: tricks with Decorators
The Self Decorator limits the search for the dependency to the current injector. · The SkipSelf Decorator doesn't look for the dependency in...
Read more >
Register Decorator In Microsoft Dependency Injection
The guide shows how to register a decorator pattern in Microsoft Dependency Injection framework.
Read more >
python - Dependency decorator with no duplictates
You need to check wether any of the dependency function has been decorated in this way, and exclude their dependencies from the ones...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found