Movatterモバイル変換


[0]ホーム

URL:


Skip to content
Join theFastAPI Cloud waiting list 🚀
Follow@fastapi onX (Twitter) to stay updated
FollowFastAPI onLinkedIn to stay updated
Subscribe to theFastAPI and friends newsletter 🎉
sponsor
sponsor
sponsor
sponsor
sponsor
sponsor
sponsor
sponsor
sponsor
sponsor
sponsor

Classes as Dependencies

Before diving deeper into theDependency Injection system, let's upgrade the previous example.

Adict from the previous example

In the previous example, we were returning adict from our dependency ("dependable"):

fromtypingimportAnnotatedfromfastapiimportDepends,FastAPIapp=FastAPI()asyncdefcommon_parameters(q:str|None=None,skip:int=0,limit:int=100):return{"q":q,"skip":skip,"limit":limit}@app.get("/items/")asyncdefread_items(commons:Annotated[dict,Depends(common_parameters)]):returncommons@app.get("/users/")asyncdefread_users(commons:Annotated[dict,Depends(common_parameters)]):returncommons
🤓 Other versions and variants

Tip

Prefer to use theAnnotated version if possible.

fromfastapiimportDepends,FastAPIapp=FastAPI()asyncdefcommon_parameters(q:str|None=None,skip:int=0,limit:int=100):return{"q":q,"skip":skip,"limit":limit}@app.get("/items/")asyncdefread_items(commons:dict=Depends(common_parameters)):returncommons@app.get("/users/")asyncdefread_users(commons:dict=Depends(common_parameters)):returncommons

But then we get adict in the parametercommons of thepath operation function.

And we know that editors can't provide a lot of support (like completion) fordicts, because they can't know their keys and value types.

We can do better...

What makes a dependency

Up to now you have seen dependencies declared as functions.

But that's not the only way to declare dependencies (although it would probably be the more common).

The key factor is that a dependency should be a "callable".

A "callable" in Python is anything that Python can "call" like a function.

So, if you have an objectsomething (that mightnot be a function) and you can "call" it (execute it) like:

something()

or

something(some_argument,some_keyword_argument="foo")

then it is a "callable".

Classes as dependencies

You might notice that to create an instance of a Python class, you use that same syntax.

For example:

classCat:def__init__(self,name:str):self.name=namefluffy=Cat(name="Mr Fluffy")

In this case,fluffy is an instance of the classCat.

And to createfluffy, you are "calling"Cat.

So, a Python class is also acallable.

Then, inFastAPI, you could use a Python class as a dependency.

What FastAPI actually checks is that it is a "callable" (function, class or anything else) and the parameters defined.

If you pass a "callable" as a dependency inFastAPI, it will analyze the parameters for that "callable", and process them in the same way as the parameters for apath operation function. Including sub-dependencies.

That also applies to callables with no parameters at all. The same as it would be forpath operation functions with no parameters.

Then, we can change the dependency "dependable"common_parameters from above to the classCommonQueryParams:

fromtypingimportAnnotatedfromfastapiimportDepends,FastAPIapp=FastAPI()fake_items_db=[{"item_name":"Foo"},{"item_name":"Bar"},{"item_name":"Baz"}]classCommonQueryParams:def__init__(self,q:str|None=None,skip:int=0,limit:int=100):self.q=qself.skip=skipself.limit=limit@app.get("/items/")asyncdefread_items(commons:Annotated[CommonQueryParams,Depends(CommonQueryParams)]):response={}ifcommons.q:response.update({"q":commons.q})items=fake_items_db[commons.skip:commons.skip+commons.limit]response.update({"items":items})returnresponse
🤓 Other versions and variants

Tip

Prefer to use theAnnotated version if possible.

fromfastapiimportDepends,FastAPIapp=FastAPI()fake_items_db=[{"item_name":"Foo"},{"item_name":"Bar"},{"item_name":"Baz"}]classCommonQueryParams:def__init__(self,q:str|None=None,skip:int=0,limit:int=100):self.q=qself.skip=skipself.limit=limit@app.get("/items/")asyncdefread_items(commons:CommonQueryParams=Depends(CommonQueryParams)):response={}ifcommons.q:response.update({"q":commons.q})items=fake_items_db[commons.skip:commons.skip+commons.limit]response.update({"items":items})returnresponse

Pay attention to the__init__ method used to create the instance of the class:

fromtypingimportAnnotatedfromfastapiimportDepends,FastAPIapp=FastAPI()fake_items_db=[{"item_name":"Foo"},{"item_name":"Bar"},{"item_name":"Baz"}]classCommonQueryParams:def__init__(self,q:str|None=None,skip:int=0,limit:int=100):self.q=qself.skip=skipself.limit=limit@app.get("/items/")asyncdefread_items(commons:Annotated[CommonQueryParams,Depends(CommonQueryParams)]):response={}ifcommons.q:response.update({"q":commons.q})items=fake_items_db[commons.skip:commons.skip+commons.limit]response.update({"items":items})returnresponse
🤓 Other versions and variants

Tip

Prefer to use theAnnotated version if possible.

fromfastapiimportDepends,FastAPIapp=FastAPI()fake_items_db=[{"item_name":"Foo"},{"item_name":"Bar"},{"item_name":"Baz"}]classCommonQueryParams:def__init__(self,q:str|None=None,skip:int=0,limit:int=100):self.q=qself.skip=skipself.limit=limit@app.get("/items/")asyncdefread_items(commons:CommonQueryParams=Depends(CommonQueryParams)):response={}ifcommons.q:response.update({"q":commons.q})items=fake_items_db[commons.skip:commons.skip+commons.limit]response.update({"items":items})returnresponse

...it has the same parameters as our previouscommon_parameters:

fromtypingimportAnnotatedfromfastapiimportDepends,FastAPIapp=FastAPI()asyncdefcommon_parameters(q:str|None=None,skip:int=0,limit:int=100):return{"q":q,"skip":skip,"limit":limit}@app.get("/items/")asyncdefread_items(commons:Annotated[dict,Depends(common_parameters)]):returncommons@app.get("/users/")asyncdefread_users(commons:Annotated[dict,Depends(common_parameters)]):returncommons
🤓 Other versions and variants

Tip

Prefer to use theAnnotated version if possible.

fromfastapiimportDepends,FastAPIapp=FastAPI()asyncdefcommon_parameters(q:str|None=None,skip:int=0,limit:int=100):return{"q":q,"skip":skip,"limit":limit}@app.get("/items/")asyncdefread_items(commons:dict=Depends(common_parameters)):returncommons@app.get("/users/")asyncdefread_users(commons:dict=Depends(common_parameters)):returncommons

Those parameters are whatFastAPI will use to "solve" the dependency.

In both cases, it will have:

  • An optionalq query parameter that is astr.
  • Askip query parameter that is anint, with a default of0.
  • Alimit query parameter that is anint, with a default of100.

In both cases the data will be converted, validated, documented on the OpenAPI schema, etc.

Use it

Now you can declare your dependency using this class.

fromtypingimportAnnotatedfromfastapiimportDepends,FastAPIapp=FastAPI()fake_items_db=[{"item_name":"Foo"},{"item_name":"Bar"},{"item_name":"Baz"}]classCommonQueryParams:def__init__(self,q:str|None=None,skip:int=0,limit:int=100):self.q=qself.skip=skipself.limit=limit@app.get("/items/")asyncdefread_items(commons:Annotated[CommonQueryParams,Depends(CommonQueryParams)]):response={}ifcommons.q:response.update({"q":commons.q})items=fake_items_db[commons.skip:commons.skip+commons.limit]response.update({"items":items})returnresponse
🤓 Other versions and variants

Tip

Prefer to use theAnnotated version if possible.

fromfastapiimportDepends,FastAPIapp=FastAPI()fake_items_db=[{"item_name":"Foo"},{"item_name":"Bar"},{"item_name":"Baz"}]classCommonQueryParams:def__init__(self,q:str|None=None,skip:int=0,limit:int=100):self.q=qself.skip=skipself.limit=limit@app.get("/items/")asyncdefread_items(commons:CommonQueryParams=Depends(CommonQueryParams)):response={}ifcommons.q:response.update({"q":commons.q})items=fake_items_db[commons.skip:commons.skip+commons.limit]response.update({"items":items})returnresponse

FastAPI calls theCommonQueryParams class. This creates an "instance" of that class and the instance will be passed as the parametercommons to your function.

Type annotation vsDepends

Notice how we writeCommonQueryParams twice in the above code:

commons:Annotated[CommonQueryParams,Depends(CommonQueryParams)]

Tip

Prefer to use theAnnotated version if possible.

commons:CommonQueryParams=Depends(CommonQueryParams)

The lastCommonQueryParams, in:

...Depends(CommonQueryParams)

...is whatFastAPI will actually use to know what is the dependency.

It is from this one that FastAPI will extract the declared parameters and that is what FastAPI will actually call.


In this case, the firstCommonQueryParams, in:

commons:Annotated[CommonQueryParams,...

Tip

Prefer to use theAnnotated version if possible.

commons:CommonQueryParams...

...doesn't have any special meaning forFastAPI. FastAPI won't use it for data conversion, validation, etc. (as it is using theDepends(CommonQueryParams) for that).

You could actually write just:

commons:Annotated[Any,Depends(CommonQueryParams)]

Tip

Prefer to use theAnnotated version if possible.

commons=Depends(CommonQueryParams)

...as in:

fromtypingimportAnnotated,AnyfromfastapiimportDepends,FastAPIapp=FastAPI()fake_items_db=[{"item_name":"Foo"},{"item_name":"Bar"},{"item_name":"Baz"}]classCommonQueryParams:def__init__(self,q:str|None=None,skip:int=0,limit:int=100):self.q=qself.skip=skipself.limit=limit@app.get("/items/")asyncdefread_items(commons:Annotated[Any,Depends(CommonQueryParams)]):response={}ifcommons.q:response.update({"q":commons.q})items=fake_items_db[commons.skip:commons.skip+commons.limit]response.update({"items":items})returnresponse
🤓 Other versions and variants

Tip

Prefer to use theAnnotated version if possible.

fromfastapiimportDepends,FastAPIapp=FastAPI()fake_items_db=[{"item_name":"Foo"},{"item_name":"Bar"},{"item_name":"Baz"}]classCommonQueryParams:def__init__(self,q:str|None=None,skip:int=0,limit:int=100):self.q=qself.skip=skipself.limit=limit@app.get("/items/")asyncdefread_items(commons=Depends(CommonQueryParams)):response={}ifcommons.q:response.update({"q":commons.q})items=fake_items_db[commons.skip:commons.skip+commons.limit]response.update({"items":items})returnresponse

But declaring the type is encouraged as that way your editor will know what will be passed as the parametercommons, and then it can help you with code completion, type checks, etc:

Shortcut

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

commons:Annotated[CommonQueryParams,Depends(CommonQueryParams)]

Tip

Prefer to use theAnnotated version if possible.

commons:CommonQueryParams=Depends(CommonQueryParams)

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

For those specific cases, you can do the following:

Instead of writing:

commons:Annotated[CommonQueryParams,Depends(CommonQueryParams)]

Tip

Prefer to use theAnnotated version if possible.

commons:CommonQueryParams=Depends(CommonQueryParams)

...you write:

commons:Annotated[CommonQueryParams,Depends()]

Tip

Prefer to use theAnnotated version if possible.

commons:CommonQueryParams=Depends()

You declare the dependency as the type of the parameter, and you useDepends() without any parameter, instead of having to write the full classagain inside ofDepends(CommonQueryParams).

The same example would then look like:

fromtypingimportAnnotatedfromfastapiimportDepends,FastAPIapp=FastAPI()fake_items_db=[{"item_name":"Foo"},{"item_name":"Bar"},{"item_name":"Baz"}]classCommonQueryParams:def__init__(self,q:str|None=None,skip:int=0,limit:int=100):self.q=qself.skip=skipself.limit=limit@app.get("/items/")asyncdefread_items(commons:Annotated[CommonQueryParams,Depends()]):response={}ifcommons.q:response.update({"q":commons.q})items=fake_items_db[commons.skip:commons.skip+commons.limit]response.update({"items":items})returnresponse
🤓 Other versions and variants

Tip

Prefer to use theAnnotated version if possible.

fromfastapiimportDepends,FastAPIapp=FastAPI()fake_items_db=[{"item_name":"Foo"},{"item_name":"Bar"},{"item_name":"Baz"}]classCommonQueryParams:def__init__(self,q:str|None=None,skip:int=0,limit:int=100):self.q=qself.skip=skipself.limit=limit@app.get("/items/")asyncdefread_items(commons:CommonQueryParams=Depends()):response={}ifcommons.q:response.update({"q":commons.q})items=fake_items_db[commons.skip:commons.skip+commons.limit]response.update({"items":items})returnresponse

...andFastAPI will know what to do.

Tip

If that seems more confusing than helpful, disregard it, you don'tneed it.

It is just a shortcut. BecauseFastAPI cares about helping you minimize code repetition.


[8]ページ先頭

©2009-2026 Movatter.jp