A minimal, lightweight mediator implementation for Python applications supporting CQRS pattern with commands and queries
Project description
livehop-minimal-mediator
A minimal, lightweight mediator implementation for Python applications supporting the CQRS pattern with commands and queries.
Features
- ✨ Minimal and lightweight - Simple implementation with no unnecessary complexity
- 🚀 Easy to use - Clean, intuitive API
- 🎯 CQRS support - Perfect for implementing commands and queries
- ⚡ Async/Await - Full async support for modern Python applications
- 🔧 Type hints - Fully typed for better IDE support and type checking
- 📦 Zero dependencies - No external dependencies required
Installation
pip install livehop-minimal-mediator
Quick Start
1. Create a Query/Command
from livehop_minimal_mediator import IRequest, IRequestHandler
# Define your request
class GetUsersQuery(IRequest[list[dict]]):
pass
# Define your handler
class GetUsersHandler(IRequestHandler[list[dict]]):
async def handle(self, request: GetUsersQuery) -> list[dict]:
# Your logic here
users = [
{"id": 1, "name": "John Doe"},
{"id": 2, "name": "Jane Smith"}
]
return users
2. Register and Use
from livehop_minimal_mediator import Mediator
import asyncio
# Create mediator instance
mediator = Mediator()
# Register handler
mediator.register_handler(GetUsersQuery, lambda: GetUsersHandler())
# Create sender
sender = mediator.create_sender()
# Use it
async def main():
query = GetUsersQuery()
users = await sender.send(query)
print(users)
asyncio.run(main())
Usage Examples
Command with Parameters
from dataclasses import dataclass
from livehop_minimal_mediator import IRequest, IRequestHandler
@dataclass
class CreateUserCommand(IRequest[int]):
name: str
email: str
class CreateUserHandler(IRequestHandler[int]):
def __init__(self, db_connection):
self.db = db_connection
async def handle(self, request: CreateUserCommand) -> int:
# Insert user logic
user_id = await self.db.insert_user(request.name, request.email)
return user_id
# Register with dependencies
mediator.register_handler(
CreateUserCommand,
lambda: CreateUserHandler(db_connection)
)
# Use it
command = CreateUserCommand(name="Alice", email="alice@example.com")
user_id = await sender.send(command)
Query with Parameters
@dataclass
class GetUserByIdQuery(IRequest[dict | None]):
user_id: int
class GetUserByIdHandler(IRequestHandler[dict | None]):
def __init__(self, db_connection):
self.db = db_connection
async def handle(self, request: GetUserByIdQuery) -> dict | None:
user = await self.db.get_user(request.user_id)
return user
# Register and use
mediator.register_handler(
GetUserByIdQuery,
lambda: GetUserByIdHandler(db_connection)
)
query = GetUserByIdQuery(user_id=1)
user = await sender.send(query)
Integration with FastAPI
from fastapi import FastAPI, Depends
from livehop_minimal_mediator import Mediator, Sender
app = FastAPI()
# Create a global mediator instance
_mediator = Mediator()
# Register all your handlers
_mediator.register_handler(GetUsersQuery, lambda: GetUsersHandler())
_mediator.register_handler(CreateUserCommand, lambda: CreateUserHandler(db))
# Create dependency
def get_sender() -> Sender:
return _mediator.create_sender()
# Use in routes
@app.get("/users")
async def get_users(sender: Sender = Depends(get_sender)):
query = GetUsersQuery()
users = await sender.send(query)
return users
@app.post("/users")
async def create_user(name: str, email: str, sender: Sender = Depends(get_sender)):
command = CreateUserCommand(name=name, email=email)
user_id = await sender.send(command)
return {"id": user_id}
Integration with Django
from django.http import JsonResponse
from livehop_minimal_mediator import Mediator
# In your settings or app config
mediator = Mediator()
mediator.register_handler(GetUsersQuery, lambda: GetUsersHandler())
# In your views
async def get_users_view(request):
sender = mediator.create_sender()
query = GetUsersQuery()
users = await sender.send(query)
return JsonResponse({"users": users})
Core Interfaces
IRequest[TResponse]
Marker interface for requests that return a response.
class MyQuery(IRequest[MyReturnType]):
pass
IRequestHandler[TResponse]
Interface for handling requests.
class MyHandler(IRequestHandler[MyReturnType]):
async def handle(self, request: MyQuery) -> MyReturnType:
# Your logic here
pass
Mediator
Manages registration and retrieval of request handlers.
mediator = Mediator()
mediator.register_handler(MyQuery, lambda: MyHandler())
sender = mediator.create_sender()
Sender
Dispatches requests to their registered handlers.
result = await sender.send(MyQuery())
Best Practices
- Organize by Feature - Group requests and handlers together in feature modules
- Use Dataclasses - Leverage dataclasses for clean, immutable request definitions
- Async All the Way - Use async/await consistently throughout your handlers
- Dependency Injection - Inject dependencies into handler constructors via factories
- Single Responsibility - Keep handlers focused on one task
Why livehop-minimal-mediator?
- Simplicity: No complex pipeline behaviors or middleware - just requests and handlers
- Lightweight: No dependencies, minimal code footprint
- Pythonic: Idiomatic Python with type hints and async support
- Transparent: Simple, readable implementation you can understand and trust
Requirements
- Python 3.8 or later
- No external dependencies
License
MIT
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Support
If you encounter any issues or have questions, please file an issue on GitHub.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file livehop_minimal_mediator-1.1.0.tar.gz.
File metadata
- Download URL: livehop_minimal_mediator-1.1.0.tar.gz
- Upload date:
- Size: 6.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8229fe251c34171738bb18a88988911148e8e2d3e6f514cd3cefa40bcc9a1eef
|
|
| MD5 |
f06e44777cdd8ef1725aeb2480481478
|
|
| BLAKE2b-256 |
12affb8e14ac26d8b77c9702c6b24869db949d17e591fb9b82adb29d22f6a49d
|
File details
Details for the file livehop_minimal_mediator-1.1.0-py3-none-any.whl.
File metadata
- Download URL: livehop_minimal_mediator-1.1.0-py3-none-any.whl
- Upload date:
- Size: 7.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f364009b35e71be999f92b23e9e5a96b046cb21c6b70773b8b10012ffd188d9f
|
|
| MD5 |
5b888a1c3baf91436d57f6d1b71eb6a0
|
|
| BLAKE2b-256 |
1a5a671586f3c6e1879484b8751f82687cf2b1d891e732c54f35d40e106c60f1
|