Dependency injection¶
Dependency injection is a programming technique that makes a class independent of its dependencies. It achieves that by decoupling the usage of an object from its creation. This helps you to follow SOLID’s dependency inversion and single responsibility principles.
How it works in aiogram¶
For each update aiogram.dispatcher.dispatcher.Dispatcher
passes handling context data.
Filters and middleware can also make changes to the context.
To access contextual data you should specify corresponding keyword parameter in handler or filter.
For example, to get aiogram.fsm.context.FSMContext
we do it like that:
@router.message(ProfileCompletion.add_photo, F.photo)
async def add_photo(
message: types.Message, bot: Bot, state: FSMContext
) -> Any:
... # do something with photo
Injecting own dependencies¶
Aiogram provides several ways to complement / modify contextual data.
The first and easiest way is to simply specify the named arguments in
aiogram.dispatcher.dispatcher.Dispatcher
initialization, polling start methods
or aiogram.webhook.aiohttp_server.SimpleRequestHandler
initialization if you use webhooks.
async def main() -> None:
dp = Dispatcher(..., foo=42)
return await dp.start_polling(
bot, bar="Bazz"
)
Analogy for webhook:
async def main() -> None:
dp = Dispatcher(..., foo=42)
handler = SimpleRequestHandler(dispatcher=dp, bot=bot, bar="Bazz")
... # starting webhook
aiogram.dispatcher.dispatcher.Dispatcher
’s workflow data also can be supplemented
by setting values as in a dictionary:
dp = Dispatcher(...)
dp["eggs"] = Spam()
The middlewares updates the context quite often. You can read more about them on this page:
The last way is to return a dictionary from the filter:
from typing import Any, Dict, Optional, Union
from aiogram import Router
from aiogram.filters import Filter
from aiogram.types import Message, User
router = Router(name=__name__)
class HelloFilter(Filter):
def __init__(self, name: Optional[str] = None) -> None:
self.name = name
async def __call__(
self,
message: Message,
event_from_user: User,
# Filters also can accept keyword parameters like in handlers
) -> Union[bool, Dict[str, Any]]:
if message.text.casefold() == "hello":
# Returning a dictionary that will update the context data
return {"name": event_from_user.mention_html(name=self.name)}
return False
@router.message(HelloFilter())
async def my_handler(
message: Message, name: str # Now we can accept "name" as named parameter
) -> Any:
return message.answer("Hello, {name}!".format(name=name))
…or using MagicFilter with .as_(...)
method.
Using type hints¶
Note
Type-hinting middleware data is optional and is not required for the correct operation of the dispatcher. However, it is recommended to use it to improve the readability of the code.
You can use type hints to specify the type of the context data in the middlewares, filters and handlers.
The default middleware data typed dict can be found in aiogram.dispatcher.middlewares.data.MiddlewareData
.
In case when you have extended the context data, you can use the aiogram.dispatcher.middlewares.data.MiddlewareData
as a base class and specify the type hints for the new fields.
Warning
If you using type checking tools like mypy, you can experience warnings about that this type hint against Liskov substitution principle in due stricter type is not a subclass of dict[str, Any]
.
This is a known issue and it is not a bug. You can ignore this warning or use # type: ignore
comment.
Example of using type hints:
from aiogram.dispatcher.middlewares.data import MiddlewareData
class MyMiddlewareData(MiddlewareData, total=False):
my_custom_value: int
class MyMessageMiddleware(BaseMiddleware):
async def __call__(
self,
handler: Callable[[Message, MyMiddlewareData], Awaitable[Any]],
event: Message,
data: MyMiddlewareData,
) -> Any:
bot = data["bot"] # <-- IDE will show you that data has `bot` key and its type is `Bot`
data["my_custom_value"] = bot.id * 42 # <-- IDE will show you that you can set `my_custom_value` key with int value and warn you if you try to set it with other type
return await handler(event, data)
Available context data type helpers¶
- class aiogram.dispatcher.middlewares.data.MiddlewareData[source]¶
Data passed to the handler by the middlewares.
You can add your own data by extending this class.
- dispatcher: Dispatcher¶
- bot: Bot¶
- bots: NotRequired[list[Bot]]¶
- handler: NotRequired[HandlerObject]¶
- event_context: EventContext¶
- event_thread_id: NotRequired[int]¶
- event_business_connection_id: NotRequired[str]¶
- fsm_storage: BaseStorage¶
- state: NotRequired[FSMContext]¶
- raw_state: NotRequired[str | None]¶
- class aiogram.dispatcher.middlewares.data.I18nData[source]¶
I18n related data.
Is not included by default, you need to add it to your own Data class if you need it.
- i18n: I18n¶
I18n object.
- i18n_middleware: I18nMiddleware¶
I18n middleware.