最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

python - How to pass an argument to a 'dependencies' function in FastAPI? - Stack Overflow

programmeradmin7浏览0评论

Is there a way to pass an argument to a function defined within the dependencies argument of, for instance, app.get? If there isn't, what other options exist ?

I can do the following to test a request, including examining the bearer token, before it reaches the endpoint handler:

async def verify_token(Authorization: Annotated[str, Header()]):
    # decode token and do processing based on it

@app.get("/read_items/", dependencies=[Depends(verify_token)])
async def read_items():
    return [{"item": "Foo"}, {"item": "Bar"}]

but what I really want to do is provide an argument to verify_token, like this:

@app.get("/read_items/", dependencies=[Depends(verify_token("red")])
async def read_items():
    return [{"item": "Foo"}, {"item": "Bar"}]

in this scenario verify_token would accept a string as an argument and the value of that string would be easily seen by anyone inspecting the code.

Of course this type of outcome could be produced by using a decorator:

@verify_token_decorator("red")    
@app.get("/read_items/")
async def read_items():
    return [{"item": "Foo"}, {"item": "Bar"}]

but decorators cannot inspect the contents of Request headers and so such a decorator would not be able to inspect the token.

Is there a way to do the functional equivalent of passing a value into a function within the dependencies argument of an end point?

Is there a way to pass an argument to a function defined within the dependencies argument of, for instance, app.get? If there isn't, what other options exist ?

I can do the following to test a request, including examining the bearer token, before it reaches the endpoint handler:

async def verify_token(Authorization: Annotated[str, Header()]):
    # decode token and do processing based on it

@app.get("/read_items/", dependencies=[Depends(verify_token)])
async def read_items():
    return [{"item": "Foo"}, {"item": "Bar"}]

but what I really want to do is provide an argument to verify_token, like this:

@app.get("/read_items/", dependencies=[Depends(verify_token("red")])
async def read_items():
    return [{"item": "Foo"}, {"item": "Bar"}]

in this scenario verify_token would accept a string as an argument and the value of that string would be easily seen by anyone inspecting the code.

Of course this type of outcome could be produced by using a decorator:

@verify_token_decorator("red")    
@app.get("/read_items/")
async def read_items():
    return [{"item": "Foo"}, {"item": "Bar"}]

but decorators cannot inspect the contents of Request headers and so such a decorator would not be able to inspect the token.

Is there a way to do the functional equivalent of passing a value into a function within the dependencies argument of an end point?

Share Improve this question edited Mar 20 at 11:37 Chris 35.5k10 gold badges104 silver badges250 bronze badges asked Mar 20 at 10:45 shearichardshearichard 8,3829 gold badges43 silver badges72 bronze badges 2
  • 1 In the original scenario verify_token accepts a string as an argument. What would it do with "red"? Perhaps you want a dependency factory, so verify_token("red") returns a function, closed over that value, then Depends(verify_token("red")) would work fine. – jonrsharpe Commented Mar 20 at 10:49
  • 2 As described here and here, a dependency is just a function that can take all the same parameters that an endpoint could take. Hence, one could simply declare the parameter(s) in the dependency function, in the same way they would be declared in the endpoint. Using a dependency class might be another way as well. – Chris Commented Mar 20 at 11:36
Add a comment  | 

2 Answers 2

Reset to default 3

The parameter to Depends() can be any Python callable. The FastAPI Advanced Dependencies guide has a couple examples, specifically oriented around classes. But in your example, so long as verify_token("red") returns a callable with the right syntax and type annotations, FastAPI can use it as a dependency.

The easy way is to have the function return another function:

def verify_token(color: str) -> Callable[[str], None]:
  async def verifier(Authorization: Annotated[str, Header()]):
    ...
  return verifier

@app.get("/read_items/", dependencies=[Depends(verify_token("red"))])
async def read_items():
  ...

The class-based approach shown in the documentation would work too. Any (fixed) parameters you pass inside the Depends() would be passed to the __init__ constructor, and any runtime parameters would be passed to __call__.

class TokenVerifier:
  def __init__(self, color: str):
    self.color = color

  def __call__(self, Authorization: Annotated[str, Header()]):
    ...

@app.get("/read_items/", dependencies=[Depends(TokenVerifier("red"))])
async def read_items():
  ...

You should refer to Advanced dependencies part of FastAPI documentation. You can create class-based dependency and parametrize it as you wish.

It differs a bit from your example, but it might be a bit more clear. Here's the example:

from typing import Annotated

from fastapi import Depends, FastAPI

app = FastAPI()


class TokenVerifier:
    def __init__(self, tag: str):
        self.tag = tag

    def __call__(self):
        pass


RedTokenVerifier = TokenVerifier("red")


@app.get("/read_items/")
async def read_items(dependencies=Depends(RedTokenVerifier)):
    return [{"item": "Foo"}, {"item": "Bar"}]

This code helps you remove magic constants from the code (I mean string 'red') and the reader of your code will still be able to see what token verification was used.

发布评论

评论列表(0)

  1. 暂无评论