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?
2 Answers
Reset to default 3The 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.
verify_token
accepts a string as an argument. What would it do with"red"
? Perhaps you want a dependency factory, soverify_token("red")
returns a function, closed over that value, thenDepends(verify_token("red"))
would work fine. – jonrsharpe Commented Mar 20 at 10:49