pythonfastapi

How to pass an argument to a 'dependencies' function in FastAPI?


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?


Solution

  • 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():
      ...