1
class User(BaseModel):
    name: str
    token: str

fake_db = [
    User(name='foo', token='a1'),
    User(name='bar', token='a2')
]

async def get_user_by_token(token: str = Header()):
    for user in fake_db:
        if user.token == token:
            return user
        else:
            raise HTTPException(status_code=401, detail='Invalid token')


@router.get(path='/test_a', summary='Test route A')
async def test_route_a(user: User = Depends(get_user_by_token)):
    return {'name': user.name}


@router.get(path='/test_b', summary='Test route B')
async def test_route_a(user: User = Depends(get_user_by_token)):
    return {'name': user.name}

I would like to avoid code duplication. Is it possible to somehow set the line user: User = Depends(get_user_by_token) for the entire router? At the same time, I need the user object to be available in each method.

It is very important that the openapi says that you need to specify a header with a token for the method.
enter image description here

kshnkvn
  • 876
  • 2
  • 18
  • 31
  • Does this answer your question? [How to add a custom decorator to a FastAPI route?](https://stackoverflow.com/questions/64497615/how-to-add-a-custom-decorator-to-a-fastapi-route) – Weder Ribas Oct 10 '22 at 18:31
  • @WederRibas no because it just does token verification but i need to get the user object in the method – kshnkvn Oct 10 '22 at 18:36
  • TMK, if you want the return value of the dependency, you have to specify it on each individual endpoint method – Mike B Oct 12 '22 at 21:46

1 Answers1

2

You can use the dependencies parameter to add global dependencies when creating the router instance:

router = APIRouter(dependencies=[Depends(get_user_by_token)])

or, when adding the router to the app instance:

app.include_router(router, dependencies=[Depends(get_user_by_token)])

Please have a look at FastAPI's documentation on Dependencies for more details.

As for getting the return value of a global dependency, you can't really do that. The way around this issue is to store the returned value to request.state (as described here), which is used to store arbitrary state (see the implementation of State as well). Hence, you could have something like this:

def get_user_by_token(request: Request, token: str = Header()):
    for user in fake_db:
        if user.token == token:
            request.state.user = user
    # ...

Then, inside your endpoint, you could retrieve the user object using request.state.user, as described in this answer.

Chris
  • 18,724
  • 6
  • 46
  • 80
  • i know i can do that, but how can i get the data that the ```get_user_by_token``` function returns? – kshnkvn Oct 10 '22 at 19:25
  • @kshnkvn You add it to the function where you need it as well. The result from the dependency will be cached, so it isn't reevaluated. Or you can use `request.state` as Christ has edited to show; but generally I prefer using the dependency in both locations, as it makes it more expressive about which values are available to the controller function. – MatsLindh Oct 10 '22 at 19:40