https://github.com/astralmortem/aiogram-dependency
A FastAPI-style dependency injection system for aiogram Telegram bots. This library brings clean, type-safe dependency injection to your aiogram handlers, making your code more modular, testable, and maintainable.
https://github.com/astralmortem/aiogram-dependency
aiogram dependency-injection fastapi telegram telegrambot
Last synced: 2 months ago
JSON representation
A FastAPI-style dependency injection system for aiogram Telegram bots. This library brings clean, type-safe dependency injection to your aiogram handlers, making your code more modular, testable, and maintainable.
- Host: GitHub
- URL: https://github.com/astralmortem/aiogram-dependency
- Owner: AstralMortem
- Created: 2025-07-21T17:31:40.000Z (11 months ago)
- Default Branch: main
- Last Pushed: 2025-07-21T17:38:22.000Z (11 months ago)
- Last Synced: 2025-07-21T18:13:15.293Z (11 months ago)
- Topics: aiogram, dependency-injection, fastapi, telegram, telegrambot
- Language: Python
- Homepage:
- Size: 0 Bytes
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Aiogram Dependency Injection
A FastAPI-style dependency injection system for aiogram Telegram bots. This library brings clean, type-safe dependency injection to your aiogram handlers, making your code more modular, testable, and maintainable.
[](https://pepy.tech/projects/aiogram-dependency)
## Features
- **FastAPI-style syntax** - Familiar `Depends()` decorator
- **Multiple dependency scopes** - Singleton, Request, and Transient
- **Nested dependencies** - Dependencies can depend on other dependencies
- **Async support** - Both sync and async dependency functions
- **Circular dependency detection** - Prevents infinite loops
- **Type-safe** - Full type hints support
- **Smart caching** - Efficient resource management
- **FastAPI Support** - Can use fastapi Depends instead default one
## Installation
```bash
pip install aiogram-dependency
```
Or install from source:
```bash
git clone https://github.com/AstralMortem/aiogram-dependency
cd aiogram-dependency
pip install -e .
```
## Quick Start
```python
import asyncio
from aiogram import Bot, Dispatcher, F
from aiogram.types import Message
from aiogram_dependency import Depends, setup_dependency, Scope
# Define your dependencies
class DatabaseConnection:
def __init__(self, connection_string: str):
self.connection_string = connection_string
async def query(self, sql: str):
# Your database logic here
return f"Result for: {sql}"
class UserService:
def __init__(self, db: DatabaseConnection):
self.db = db
async def get_user_profile(self, user_id: int):
return await self.db.query(f"SELECT * FROM users WHERE id = {user_id}")
# Dependency factories
async def get_database() -> DatabaseConnection:
return DatabaseConnection("postgresql://localhost/mydb")
async def get_user_service(
db: DatabaseConnection = Depends(get_database, scope=Scope.SINGLETON)
) -> UserService:
return UserService(db)
# Handler with dependency injection
async def profile_handler(
message: Message,
user_service: UserService = Depends(get_user_service)
):
if not message.from_user:
await message.answer("User not found")
return
profile = await user_service.get_user_profile(message.from_user.id)
await message.answer(f"Your profile: {profile}")
# Setup bot (ORDER MATER!)
async def main():
bot = Bot(token="YOUR_BOT_TOKEN")
dp = Dispatcher()
# Register handlers
dp.message.register(profile_handler, F.text == "/profile")
# Register dependency injection
setup_dependency(dp)
await dp.start_polling(bot)
if __name__ == "__main__":
asyncio.run(main())
```
## Dependency Scopes
### Singleton
Created once and shared across all requests globally.
```python
async def get_database() -> DatabaseConnection:
return DatabaseConnection("connection_string")
async def handler(
message: Message,
db: DatabaseConnection = Depends(get_database, scope=Scope.SINGLETON)
):
# Same database instance for all users
pass
```
### Request (Default)
Created once per user/chat and cached for subsequent calls in the same context.
```python
async def get_user_service() -> UserService:
return UserService()
async def handler(
message: Message,
service: UserService = Depends(get_user_service, scope=Scope.REQUEST)
):
# Same service instance for this user, different for other users
pass
```
### Transient
Created fresh every time it's requested.
```python
async def get_timestamp() -> float:
return time.time()
async def handler(
message: Message,
timestamp: float = Depends(get_timestamp, scope=Scope.TRANSIENT)
):
# New timestamp every time
pass
```
## Advanced Usage
### FastAPI
You can use FastAPI Depends to remove dupplication if you use fastapi as backend server
### Annotated
You can use Annotated type to make it more readable.
```python
from typing import Annotated
from aiogram_dependency import Depends
from aiogram import Dispatcher,filters,types
async def get_database() -> DatabaseConnection:
return DatabaseConnection("postgresql://localhost/db")
DatabaseDep = Annotated[DatabaseConnection, Depends(get_database)]
async def get_user(db: DatabaseDep):
return db.execute('SQL')
UserDep = Annotated[dict, Depends(get_user)]
dp = Dispatcher()
@dp.message(filters.CommandStart())
async def start(message:types.Message, user: UserDep):
return await message.answer(user['username'])
```
### Nested Dependencies
Dependencies can depend on other dependencies:
```python
async def get_database() -> DatabaseConnection:
return DatabaseConnection("postgresql://localhost/db")
async def get_user_repository(
db: DatabaseConnection = Depends(get_database)
) -> UserRepository:
return UserRepository(db)
async def get_user_service(
user_repo: UserRepository = Depends(get_user_repository),
notification_service: NotificationService = Depends(get_notification_service)
) -> UserService:
return UserService(user_repo, notification_service)
```
### Using Event Data in Dependencies
Dependencies can access the current event and handler data:
```python
async def get_current_user(event: Message) -> Optional[User]:
return event.from_user
async def get_user_permissions(
event: Message,
data: dict,
current_user: User = Depends(get_current_user)
) -> List[str]:
# Access event, data, and other dependencies
if current_user and current_user.id in data.get('admins', []):
return ['admin', 'user']
return ['user']
async def admin_handler(
message: Message,
permissions: List[str] = Depends(get_user_permissions)
):
if 'admin' not in permissions:
await message.answer("Access denied")
return
await message.answer("Welcome, admin!")
```
### Custom Registry and Resolver
For advanced use cases, you can customize the dependency system:
```python
from aiogram_dependency.registry import DependencyRegistry
from aiogram_dependency.resolver import DependencyResolver
from aiogram_dependency.middleware import DependencyMiddleware
from aiogram_dependency import Scope
# Create custom registry
registry = DependencyRegistry()
db_dep = Depends(get_database, scope=Scope.SINGLETON)
# Pre-populate with some dependencies
registry.set_dependency(
db_dep,
DatabaseConnection("custom://connection"),
"global"
)
# Use custom middleware
middleware = DependencyMiddleware(registry)
dp.message.middleware(middleware)
```
## Testing
The library is fully testable. Here's an example:
Run the full test suite:
```bash
# Install test dependencies
pip install pytest pytest-asyncio
# Run tests
pytest tests/ -v
# Run with coverage
pytest tests/ --cov=aiogram_dependency --cov-report=html
```
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## Related Projects
- [aiogram](https://github.com/aiogram/aiogram) - Modern and fully asynchronous framework for Telegram Bot API
- [FastAPI](https://github.com/tiangolo/fastapi) - Modern, fast web framework for building APIs with Python