Pipeline Behaviors
Pipeline behaviors in Bazario enable pre- and post-processing logic for requests and notifications. These behaviors form a chain around the core handler logic and can modify or enhance the data flow.
Defining Pipeline Behaviors
from bazario import (
PipelineBehavior,
Resolver,
HandleNext,
Request,
Notification,
)
# Behavior for all requests
from bazario import PipelineBehavior, HandleNext, Request
class AuthenticationCheckBehavior(PipelineBehavior[Request, Any]):
def __init__(self, user_provider: UserProvider) -> None:
self._user_provider = user_provider
def handle(self, request: Request, handle_next: HandleNext[Request, Any]) -> Any:
# Check if user is authenticated
if not self._user_provider.is_authenticated():
raise PermissionError("User is not authenticated.")
# Proceed to the next handler or behavior
return handle_next(request)
# Behavior for all notifications
class AddToEventStoreBehavior(PipelineBehavior[Notification, None]):
def __init__(self, event_store: EventStore) -> None:
self._event_store = event_store
def handle(
self,
request: Notification,
handle_next: HandleNext[Notification, None],
) -> None:
self._event_store.add(request)
return handle_next(request)
# Behavior specific to AddPost request
class AddPostValidationBehavior(PipelineBehavior[AddPost, int]):
def handle(
self,
request: AddPost,
handle_next: HandleNext[AddPost, int],
) -> int:
if not request.title:
raise ValidationError("Title required")
if not request.content:
raise ValidationError("Content required")
return handle_next(request)
# Behavior specific to PostAdded notification
class PostAddedEmailBehavior(PipelineBehavior[PostAdded, None]):
def __init__(self, email_service: EmailService) -> None:
self._email_service = email_service
def handle(self, request: PostAdded, handle_next: HandleNext[PostAdded, None]) -> None:
# Send a thank-you email to the user
self._email_service.send_email(
to_user_id=request.user_id,
subject="Thank you for adding a post!",
body=f"Dear User {request.user_id}, thank you for your post with ID {request.post_id}!"
)
# Proceed with the next behavior or handler
return handle_next(request)
Registering Pipeline Behaviors
Register your behaviors to Registry
. The order of behavior registration determines the execution sequence - behaviors are executed in the order they are added:
from bazario import Registry
def provide_registry() -> Registry:
registry = Registry()
# Behaviors will execute in this order:
# 1. AuthenticationCheckBehavior
# 2. AddToEventStoreBehavior
# 3. AddPostValidationBehavior
# 4. PostAddedEmailBehavior
registry.add_pipeline_behaviors(Request, AuthenticationCheckBehavior)
registry.add_pipeline_behaviors(Notification, AddToEventStoreBehavior)
registry.add_pipeline_behaviors(AddPost, AddPostValidationBehavior)
registry.add_pipeline_behaviors(PostAdded, PostAddedEmailBehavior)
return registry
The execution order follows these rules:
1. Global behaviors (registered for base types like Request
or Notification
) execute first
2. Specific behaviors (registered for concrete types like AddPost
or PostAdded
) execute after global ones
3. Within each category (global/specific), behaviors execute in the order they were registered
4. For a single request/notification, all applicable behaviors form a chain in this order
Example of execution flow for an AddPost
request:
def provide_registry() -> Registry:
registry = Registry()
registry.add_behaviors(Request, RequestLoggingBehavior)
registry.add_behaviors(AddPost, ValidationBehavior, MetricsBehavior)
return registry
# Execution sequence for AddPost request:
# 1. RequestLoggingBehavior
# 2. ValidationBehavior
# 3. MetricsBehavior
# 4. Actual AddPost handler
Add to your IoC Container:
# ...
container.register(Registry, provide_registry)
# ...
Benefits of Pipeline Behaviors
Pipeline behaviors solve several common issues: - Centralize cross-cutting concerns - Keep handlers focused on business logic - Enable flexible behavior execution order - Eliminate code duplication in validation and response modification