pythondependency-injectionfastapidepends

Why does FastAPI's Depends() work without any parameter passed to it?


I found the following FastAPI code for authenticating a user with their information gotten from a form:

@app.post("/token")

async def login_for_access_token(form_data:OAuth2PasswordRequestForm = Depends(),
                                 db: Session = Depends(get_db)):

    user = authenticate_user(form_data.username, form_data.password, db)
    if not user:
        raise token_exception()
    
    token_expires = timedelta(minutes=20)
    
    token = create_access_token(user.username,
                                user.id,
                                expires_delta=token_expires)
    return {"token": token}

I'm struggling to understand why in form_data:OAuth2PasswordRequestForm = Depends(), Depends() has no parameter passed to it? I thought that the whole point of Depends() was to be instantiated with a function that gets called before the endpoint function is called.


Solution

  • In order to avoid code repetition, FastAPI allows declaring the dependency as the type of the parameter, and using Depends() without any parameter in it. For instance:

    form_data: OAuth2PasswordRequestForm = Depends()
    

    Hence, since you have already declared OAuth2PasswordRequestForm as the type of the form_data parameter, there is no need to pass it to the Depends() as well.

    As per FastAPI's documentation:

    Shortcut

    But you see that we are having some code repetition here, writing CommonQueryParams twice:

    commons: CommonQueryParams = Depends(CommonQueryParams)
    

    FastAPI provides a shortcut for these cases, in where the dependency is specifically a class that FastAPI will "call" to create an instance of the class itself.

    For those specific cases, you can do the following:

    Instead of writing:

    commons: CommonQueryParams = Depends(CommonQueryParams)
    

    ...you write:

    commons: CommonQueryParams = Depends()
    

    You declare the dependency as the type of the parameter, and you use Depends() as its "default" value (that after the =) for that function's parameter, without any parameter in Depends(), instead of having to write the full class again inside of Depends(CommonQueryParams).