Classes as Dependencies

    The current page still doesn’t have a translation for this language.

    But you can help translating it: Contributing.

    Before diving deeper into the Dependency Injection system, let’s upgrade the previous example.

    In the previous example, we were returning a dict from our dependency (“dependable”):

    Python 3.10 and above

    1. from fastapi import Depends, FastAPI
    2. app = FastAPI()
    3. async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
    4. return {"q": q, "skip": skip, "limit": limit}
    5. @app.get("/items/")
    6. async def read_items(commons: dict = Depends(common_parameters)):
    7. return commons
    8. @app.get("/users/")
    9. async def read_users(commons: dict = Depends(common_parameters)):
    10. return commons

    But then we get a dict in the parameter commons of the path operation function.

    And we know that editors can’t provide a lot of support (like completion) for dicts, 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 object something (that might not be a function) and you can “call” it (execute it) like:

    1. something()

    or

    1. something(some_argument, some_keyword_argument="foo")

    then it is a “callable”.

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

    For example:

    1. class Cat:
    2. def __init__(self, name: str):
    3. self.name = name
    4. fluffy = Cat(name="Mr Fluffy")

    In this case, fluffy is an instance of the class Cat.

    And to create fluffy, you are “calling” Cat.

    Then, in FastAPI, 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 in FastAPI, it will analyze the parameters for that “callable”, and process them in the same way as the parameters for a path operation function. Including sub-dependencies.

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

    Then, we can change the dependency “dependable” common_parameters from above to the class CommonQueryParams:

    Python 3.6 and abovePython 3.10 and above

    1. from typing import Union
    2. from fastapi import Depends, FastAPI
    3. app = FastAPI()
    4. fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
    5. class CommonQueryParams:
    6. def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100):
    7. self.q = q
    8. self.skip = skip
    9. self.limit = limit
    10. @app.get("/items/")
    11. async def read_items(commons: CommonQueryParams = Depends(CommonQueryParams)):
    12. response = {}
    13. if commons.q:
    14. response.update({"q": commons.q})
    15. items = fake_items_db[commons.skip : commons.skip + commons.limit]
    16. response.update({"items": items})
    17. return response
    1. from fastapi import Depends, FastAPI
    2. app = FastAPI()
    3. fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
    4. class CommonQueryParams:
    5. def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):
    6. self.q = q
    7. self.skip = skip
    8. self.limit = limit
    9. @app.get("/items/")
    10. async def read_items(commons: CommonQueryParams = Depends(CommonQueryParams)):
    11. response = {}
    12. if commons.q:
    13. response.update({"q": commons.q})
    14. items = fake_items_db[commons.skip : commons.skip + commons.limit]
    15. response.update({"items": items})
    16. return response

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

    Python 3.6 and abovePython 3.10 and above

    1. from typing import Union
    2. from fastapi import Depends, FastAPI
    3. app = FastAPI()
    4. fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
    5. class CommonQueryParams:
    6. def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100):
    7. self.q = q
    8. self.skip = skip
    9. self.limit = limit
    10. @app.get("/items/")
    11. if commons.q:
    12. response.update({"q": commons.q})
    13. items = fake_items_db[commons.skip : commons.skip + commons.limit]
    14. response.update({"items": items})
    15. return response

    …it has the same parameters as our previous common_parameters:

    Python 3.6 and abovePython 3.10 and above

    1. from typing import Union
    2. from fastapi import Depends, FastAPI
    3. app = FastAPI()
    4. async def common_parameters(
    5. q: Union[str, None] = None, skip: int = 0, limit: int = 100
    6. ):
    7. return {"q": q, "skip": skip, "limit": limit}
    8. @app.get("/items/")
    9. async def read_items(commons: dict = Depends(common_parameters)):
    10. return commons
    11. @app.get("/users/")
    12. async def read_users(commons: dict = Depends(common_parameters)):
    13. return commons
    1. from fastapi import Depends, FastAPI
    2. app = FastAPI()
    3. async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
    4. return {"q": q, "skip": skip, "limit": limit}
    5. @app.get("/items/")
    6. async def read_items(commons: dict = Depends(common_parameters)):
    7. return commons
    8. @app.get("/users/")
    9. async def read_users(commons: dict = Depends(common_parameters)):
    10. return commons

    Those parameters are what FastAPI will use to “solve” the dependency.

    In both cases, it will have:

    • An optional q query parameter that is a str.
    • A skip query parameter that is an int, with a default of 0.
    • A limit query parameter that is an int, with a default of 100.

    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.

    Python 3.6 and abovePython 3.10 and above

    1. from typing import Union
    2. from fastapi import Depends, FastAPI
    3. app = FastAPI()
    4. fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
    5. class CommonQueryParams:
    6. def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100):
    7. self.q = q
    8. self.skip = skip
    9. self.limit = limit
    10. @app.get("/items/")
    11. async def read_items(commons: CommonQueryParams = Depends(CommonQueryParams)):
    12. response = {}
    13. if commons.q:
    14. response.update({"q": commons.q})
    15. items = fake_items_db[commons.skip : commons.skip + commons.limit]
    16. response.update({"items": items})
    17. return response
    1. from fastapi import Depends, FastAPI
    2. app = FastAPI()
    3. fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
    4. class CommonQueryParams:
    5. def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):
    6. self.q = q
    7. self.skip = skip
    8. self.limit = limit
    9. @app.get("/items/")
    10. async def read_items(commons: CommonQueryParams = Depends(CommonQueryParams)):
    11. response = {}
    12. if commons.q:
    13. response.update({"q": commons.q})
    14. items = fake_items_db[commons.skip : commons.skip + commons.limit]
    15. response.update({"items": items})
    16. return response

    FastAPI calls the CommonQueryParams class. This creates an “instance” of that class and the instance will be passed as the parameter commons to your function.

    Notice how we write CommonQueryParams twice in the above code:

    1. commons: CommonQueryParams = Depends(CommonQueryParams)

    The last CommonQueryParams, in:

    …is what FastAPI will actually use to know what is the dependency.


    In this case, the first CommonQueryParams, in:

      …doesn’t have any special meaning for FastAPI. FastAPI won’t use it for data conversion, validation, etc. (as it is using the = Depends(CommonQueryParams) for that).

      You could actually write just:

      ..as in:

      Python 3.6 and abovePython 3.10 and above

      1. from typing import Union
      2. from fastapi import Depends, FastAPI
      3. app = FastAPI()
      4. fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
      5. class CommonQueryParams:
      6. def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100):
      7. self.q = q
      8. self.skip = skip
      9. self.limit = limit
      10. @app.get("/items/")
      11. async def read_items(commons=Depends(CommonQueryParams)):
      12. response = {}
      13. if commons.q:
      14. response.update({"q": commons.q})
      15. items = fake_items_db[commons.skip : commons.skip + commons.limit]
      16. response.update({"items": items})
      17. return response
      1. from fastapi import Depends, FastAPI
      2. app = FastAPI()
      3. fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
      4. class CommonQueryParams:
      5. def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):
      6. self.q = q
      7. self.skip = skip
      8. self.limit = limit
      9. @app.get("/items/")
      10. async def read_items(commons=Depends(CommonQueryParams)):
      11. response = {}
      12. if commons.q:
      13. response.update({"q": commons.q})
      14. items = fake_items_db[commons.skip : commons.skip + commons.limit]
      15. response.update({"items": items})
      16. return response

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

      Shortcut

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

      1. 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:

      1. commons: CommonQueryParams = Depends(CommonQueryParams)

      …you write:

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

      The same example would then look like:

      Python 3.6 and abovePython 3.10 and above

      1. from typing import Union
      2. from fastapi import Depends, FastAPI
      3. app = FastAPI()
      4. fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
      5. class CommonQueryParams:
      6. def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100):
      7. self.q = q
      8. self.skip = skip
      9. self.limit = limit
      10. @app.get("/items/")
      11. async def read_items(commons: CommonQueryParams = Depends()):
      12. response = {}
      13. if commons.q:
      14. response.update({"q": commons.q})
      15. items = fake_items_db[commons.skip : commons.skip + commons.limit]
      16. response.update({"items": items})
      17. return response
      1. from fastapi import Depends, FastAPI
      2. app = FastAPI()
      3. fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
      4. class CommonQueryParams:
      5. def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):
      6. self.q = q
      7. self.skip = skip
      8. self.limit = limit
      9. @app.get("/items/")
      10. async def read_items(commons: CommonQueryParams = Depends()):
      11. response = {}
      12. if commons.q:
      13. response.update({"q": commons.q})
      14. items = fake_items_db[commons.skip : commons.skip + commons.limit]
      15. return response

      …and FastAPI will know what to do.

      Tip

      If that seems more confusing than helpful, disregard it, you don’t need it.

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