7

I am trying to implement JWT with fastapi. Currently looking at the following libraries fastapi-users FastAPI JWT Auth

In both cases, I see Depends() in method parameter. What does Depends do when there is nothing in the parameter?

https://github.com/frankie567/fastapi-users/blob/master/fastapi_users/router/auth.py

@router.post("/login")
    async def login(
        response: Response, credentials: OAuth2PasswordRequestForm = Depends()
    ):

https://indominusbyte.github.io/fastapi-jwt-auth/usage/basic/

@app.post('/login')
def login(user: User, Authorize: AuthJWT = Depends()):

I undestand when there's a function inside the parameter but would you teach me what it does when there's no parameter with Depends?

codingdaddy
  • 407
  • 5
  • 17
  • Where do you get Depends from? What do its docs say about the arguments it expects? – jonrsharpe Nov 29 '20 at 12:06
  • I'm reading this too @jonrsharpe because the docs are laid out as a couple of different levels of tutorial - there's no reference / index and topics are laid out and scattered all over the place. I can't find an example of `Depends()` in the tutorial. Have you read the docs and located where it discusses `Depends` with no parameters? Can you give us a link? - NVM! I've just read the accepted answer and now remember where the info on parameter-less `Depends` is hidden. Because it's a shortcut and actually performs as if there was a parameter it didn't come to mind. – NeilG Jan 18 '23 at 11:54

2 Answers2

7

Depends() without arguments is just a shortcut for classes as dependencies.

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).

alex_noname
  • 26,459
  • 5
  • 69
  • 86
  • 1
    It would be great to point out a mistake in my answer after downvoting – alex_noname Dec 01 '20 at 09:25
  • 1
    I think that this is the correct answer to the question asked – NicoT Dec 07 '20 at 16:34
  • This is *so* useful when you are using a dependency and modifying the body type on the fly in the path operation function in order to support all fields optional for a PATCH operation! https://stackoverflow.com/questions/67699451/make-every-fields-as-optional-with-pydantic Phew! It's so cool how FastAPI / Pydantic supports this in such a compact way. Also, you can do it just by *using* Pydantic. With Django almost every customisation requires you to dig under the sometimes undocumented cover and subclass and jiggery poke. So thankful for FastAPI. Not looking back at Django – NeilG Jan 18 '23 at 12:01
  • SO contains high rep lurkers @alex_noname who seem to like down voting questions they don't understand. It's an institutional problem that's not getting recognition, possibly because high rep users always think that high rep users are always right. – NeilG Aug 29 '23 at 09:54
2

In both cases, I see Depends() in method parameter. What does Depends do when there is nothing in the parameter?

It's a great question.

Assume you have the following code.

from fastapi import FastAPI, Depends
from pydantic import BaseModel
from typing import Optional


class Location(BaseModel):
    city: str
    country: str
    state: str


app = FastAPI()


@app.post("/withoutdepends")
async def with_depends(location: Location):
    return location


@app.post("/withdepends")
async def with_depends(location: Location = Depends()):
    return lcoation

We have the same Location model in two different endpoints, one uses Depends other one not.

What is the difference?

Since FastAPI is based on OpenAPI specification, we can start discovering the difference from auto-generated Swagger's docs.

This is without Depends, it expects a Request Body.

This is with Depends, it expects them as Query parameters.

How this is useful and how it works?

Actually, this is it, it expects a Callable there.

But when you use a Pydantic Model with Depends, it actually creates a query parameter for parameter inside init __init__ function.

So for example, this is the model we used above.

class Location(BaseModel):
    city: str
    country: str
    state: str

It becomes this with Depends.


class Location(BaseModel):
    def __init__(self, city: str, country: str, state: str) -> None:
        ...

Then they will become query parameters. This is the OpenAPI schema for the /withdepends endpoint.

"parameters": [
    {
        "required":true,
        "schema":{
            "title":"City",
            "type":"string"
        },
        "name":"city",
        "in":"query"
    },
    {
        "required":true,
        "schema":{
            "title":"Country",
            "type":"string"
        },
        "name":"country",
        "in":"query"
    },
    {
        "required":true,
        "schema":{
            "title":"State",
            "type":"string"
        },
        "name":"state",
        "in":"query"
    }
]

This is the OpenAPI schema it created for /withoutdepends endpoint.

"requestBody": {
    "content":{
        "application/json":{
            "schema":{
                "$ref":"#/components/schemas/Location"
            }
        }
    },
    "required":true
}

Conclusion

Instead of request body, you can create query parameters with the same model.

Pydantic models are very useful for the cases when you have +5 parameters. But it expects a request body by default. But OpenAPI specification doesn't allow request body in GET operations. As it says in the specification.

GET, DELETE and HEAD are no longer allowed to have request body because it does not have defined semantics as per RFC 7231.

So by using Depends you are able to create query parameters for your GET endpoint, with the same model.

Yagiz Degirmenci
  • 16,595
  • 7
  • 65
  • 85
  • OP doesn't want to know what `Depends` does in general, he wants to know specifically what `Depends()` does when it is given no parameters. – NeilG Jan 18 '23 at 11:55