Dependency injection
Status: Implemented.
Dependency injection is signature-based and contains no service container, provider graph, scopes, or FastAPI dependency model.
Resolution
For every handler parameter, resolution is deterministic:
- An annotation compatible with the current
Eventsubtype receives the event, regardless of parameter name. - An unannotated conventional alias (
event,message,action,unknown,error, orerror_event) receives the matching event. - Other parameters resolve by name from
feed_update()context, filter mappings, or middleware mutations. - An omitted parameter with a Python default uses that default.
- Otherwise
DependencyResolutionErroris raised. The error names the handler, parameter, and event type so a failure that happens before the callback body runs is still actionable.
@router.message()
async def handler(message: MessageEvent, database, label="default"):
return database, label
result = await dispatcher.feed_update(event, database=db)
Event aliases are conventional unannotated names: event, message,
action, command, added_to_space, removed_from_space, widget,
app_home, form, dialog_submit, dialog_cancel, unknown, error, and
error_event. A typed event parameter is resolved by its annotation, so the
parameter name can be arbitrary:
@router.slash_command(F.command_id == 1)
async def start(command: CommandEvent, bot: Bot) -> None:
await bot.app.messages.create(command.space.name, text="Started")
bot in this example must be supplied by the dispatcher or transport context.
Arbitrary names are not aliases and do not magically receive the event:
@router.message()
async def mistaken(name):
return name
Unless middleware or the dispatcher supplies name=..., this raises
DependencyResolutionError. Use message: MessageEvent (or another typed
event parameter) when the handler needs the event itself.
Filter mappings cannot redefine an existing key, including one from another
filter or the caller. Such collisions raise ContextConflictError instead of
depending on merge order. Middleware mutation is explicit imperative behavior
and uses normal mapping assignment.
Caching and signature limits
Handler signatures and resolved type hints compile into immutable
HandlerPlan objects cached by callback. Request-specific event and context
values are resolved anew for every dispatch and are never cached.
Positional-only parameters, *args, and **kwargs are rejected at
registration. Keyword-only parameters are supported. Handlers must return an
awaitable; a synchronous callback fails with InvalidHandlerError.