Skip to content

Commit

Permalink
docs; naming fixed
Browse files Browse the repository at this point in the history
  • Loading branch information
chessenjoyer17 committed Jan 11, 2025
1 parent 5ae91b2 commit 83421dd
Show file tree
Hide file tree
Showing 23 changed files with 519 additions and 138 deletions.
60 changes: 30 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ class AddPostHandler(RequestHandler[AddPost, int]):
### Configuring DI Framework
This example demonstrates how to configure your dependency injection (DI) framework (Dishka in this case) to work with Bazario:
```python
from bazario import Dispatcher, PipelineBehaviourRegistry
from bazario import Dispatcher, PipelineBehaviorRegistry
from bazario.plugins.dishka import (
DishkaHandlerFinder,
DishkaHandlerResolver,
Expand Down Expand Up @@ -190,15 +190,15 @@ Pipeline behaviors in **Bazario** enable pre- and post-processing logic for requ
### Defining Pipeline Behaviors
```python
from bazario import (
PipelineBehaviour,
PipelineBehavior,
Resolver,
HandleNext,
Request,
Notification,
)

# Behavior for all requests
class RequestLoggingBehaviour(PipelineBehaviour[Request, Any]):
class RequestLoggingBehavior(PipelineBehavior[Request, Any]):
def handle(
self,
resolver: Resolver,
Expand All @@ -213,7 +213,7 @@ class RequestLoggingBehaviour(PipelineBehaviour[Request, Any]):
return response

# Behavior for all notifications
class NotificationLoggingBehaviour(PipelineBehaviour[Notification, None]):
class NotificationLoggingBehavior(PipelineBehavior[Notification, None]):
def handle(
self,
resolver: Resolver,
Expand All @@ -226,7 +226,7 @@ class NotificationLoggingBehaviour(PipelineBehaviour[Notification, None]):
logger.log_info("After notification handler execution")

# Behavior specific to AddPost request
class AddPostLoggingBehaviour(PipelineBehaviour[AddPost, int]):
class AddPostLoggingBehavior(PipelineBehavior[AddPost, int]):
def handle(
self,
resolver: Resolver,
Expand All @@ -241,7 +241,7 @@ class AddPostLoggingBehaviour(PipelineBehaviour[AddPost, int]):
return response

# Behavior specific to PostAdded notification
class PostAddedLoggingBehaviour(PipelineBehaviour[PostAdded, None]):
class PostAddedLoggingBehavior(PipelineBehavior[PostAdded, None]):
def handle(
self,
resolver: Resolver,
Expand All @@ -255,22 +255,22 @@ class PostAddedLoggingBehaviour(PipelineBehaviour[PostAdded, None]):
```

### Registering Pipeline Behaviors
Define the factory function for `PipelineBehaviourRegistry`. The order of behavior registration determines the execution sequence - behaviors are executed in the order they are added:
Define the factory function for `PipelineBehaviorRegistry`. The order of behavior registration determines the execution sequence - behaviors are executed in the order they are added:

```python
from bazario import PipelineBehaviourRegistry
from bazario import PipelineBehaviorRegistry

def build_registry() -> PipelineBehaviourRegistry:
registry = PipelineBehaviourRegistry()
def build_registry() -> PipelineBehaviorRegistry:
registry = PipelineBehaviorRegistry()
# Behaviors will execute in this order:
# 1. RequestLoggingBehaviour
# 2. NotificationLoggingBehaviour
# 3. AddPostLoggingBehaviour
# 4. PostAddedLoggingBehaviour
registry.add_behaviours(Request, RequestLoggingBehaviour())
registry.add_behaviours(Notification, NotificationLoggingBehaviour())
registry.add_behaviours(AddPost, AddPostLoggingBehaviour())
registry.add_behaviours(PostAdded, PostAddedLoggingBehaviour())
# 1. RequestLoggingBehavior
# 2. NotificationLoggingBehavior
# 3. AddPostLoggingBehavior
# 4. PostAddedLoggingBehavior
registry.add_Behaviors(Request, RequestLoggingBehavior())
registry.add_Behaviors(Notification, NotificationLoggingBehavior())
registry.add_Behaviors(AddPost, AddPostLoggingBehavior())
registry.add_Behaviors(PostAdded, PostAddedLoggingBehavior())

return registry
```
Expand All @@ -283,22 +283,22 @@ The execution order follows these rules:

Example of execution flow for an `AddPost` request:
```python
def build_registry() -> PipelineBehaviourRegistry:
registry = PipelineBehaviourRegistry()
def build_registry() -> PipelineBehaviorRegistry:
registry = PipelineBehaviorRegistry()

registry.add_behaviours(Request, RequestLoggingBehaviour())
registry.add_behaviours(
registry.add_Behaviors(Request, RequestLoggingBehavior())
registry.add_Behaviors(
AddPost,
ValidationBehaviour(),
MetricsBehaviour(),
ValidationBehavior(),
MetricsBehavior(),
)

return registry

# Execution sequence for AddPost request:
# 1. RequestLoggingBehaviour
# 2. ValidationBehaviour
# 3. MetricsBehaviour
# 1. RequestLoggingBehavior
# 2. ValidationBehavior
# 3. MetricsBehavior
# 4. Actual AddPost handler
```

Expand All @@ -307,9 +307,9 @@ Configure the IoC container:
def build_container() -> Container:
# ...
main_provider.provide(build_registry)
# Note: The Dispatcher depends on PipelineBehaviourRegistry.
# If you're not using pipeline behaviors, register PipelineBehaviourRegistry directly:
# main_provider.provide(PipelineBehaviourRegistry)
# Note: The Dispatcher depends on PipelineBehaviorRegistry.
# If you're not using pipeline behaviors, register PipelineBehaviorRegistry directly:
# main_provider.provide(PipelineBehaviorRegistry)
# ...
```

Expand Down
20 changes: 20 additions & 0 deletions docs/core-concepts/ioc-integration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
This example demonstrates how to configure your dependency injection (DI) framework (Dishka in this case) to work with Bazario:
```python
from bazario import Dispatcher, PipelineBehaviourRegistry
from bazario.plugins.dishka import (
DishkaHandlerFinder,
DishkaHandlerResolver,
)
from dishka import Provider, Scope, make_container

def build_container() -> Container:
main_provider = Provider(scope=Scope.REQUEST)

main_provider.provide(AddPostHandler)
main_provider.provide(WithParents[Dispatcher])
main_provider.provide(WithParents[DishkaHandlerFinder])
main_provider.provide(WithParents[DishkaHandlerResolver])
# Additional registrations (PostRepository, TransactionCommiter, etc.)

return make_container(main_provider)
```
72 changes: 72 additions & 0 deletions docs/core-concepts/notifications-and-events.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
**Notifications** in Bazario represent events that are published in response to certain actions. They are used to notify other parts of the system about changes that have occurred, without requiring a return result.

**Notification Handlers** are responsible for processing these notifications.

Here's an example of defining a notification and its handlers:

Define notifications and their handlers:
```python
from bazario import Notification, NotificationHandler

@dataclass(frozen=True)
class PostAdded(Notification):
post_id: int
user_id: int

class PostAddedFirstHandler(NotificationHandler[PostAdded]):
def handle(self, notification: PostAdded) -> None:
logger.info(
"Post first added: post_id=%s, user_id=%s",
notification.post_id, notification.user_id,
)

class PostAddedSecondHandler(NotificationHandler[PostAdded]):
def handle(self, notification: PostAdded) -> None:
logger.info(
"Post second added: post_id=%s, user_id=%s",
notification.post_id, notification.user_id,
)
```
Register handlers in your container:
``` python
def build_container() -> Container:
# ...
main_provider.provide(PostAddedFirstHandler)
main_provider.provide(PostAddedSecondHandler)
# ...
```
Implementation of notification publication within the request handler:
``` python
from bazario import Publisher

class AddPostHandler(RequestHandler[AddPost, int]):
def __init__(
self,
publisher: Publisher, # for notification publishing
post_factory: PostFactory,
user_provider: UserProvider,
post_repository: PostRepository,
transaction_commiter: TransactionCommiter,
) -> None:
self._publisher = publisher
self._post_factory = post_factory
self._user_provider = user_provider
self._post_repository = post_repository
self._transaction_commiter = transaction_commiter

def handle(self, request: AddPost) -> int:
user_id = self._user_provider.get_id()
new_post = self._post_factory.create(
title=request.title,
content=request.content,
owner_id=user_id,
)
self._post_repository.add(new_post)
self._publisher.publish(PostAdded(
post_id=new_post.id,
user_id=user_id,
)) # notification publishing
self._transaction_commiter.commit()

return new_post.id
```
134 changes: 134 additions & 0 deletions docs/core-concepts/pipeline-behaviors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
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
```python
from bazario import (
PipelineBehavior,
Resolver,
HandleNext,
Request,
Notification,
)

# Behavior for all requests
class RequestLoggingBehavior(PipelineBehavior[Request, Any]):
def handle(
self,
resolver: Resolver,
target: Request,
handle_next: HandleNext[Request, Any],
) -> Any:
logger = resolver.resolve(Logger)
logger.log_info("Before request handler execution")
response = handle_next(resolver, target)
logger.log_info(f"After request handler execution. Response: {response}")

return response

# Behavior for all notifications
class NotificationLoggingBehavior(PipelineBehavior[Notification, None]):
def handle(
self,
resolver: Resolver,
target: Notification,
handle_next: HandleNext[Notification, None],
) -> None:
logger = resolver.resolve(Logger)
logger.log_info("Before notification handler execution")
handle_next(resolver, target)
logger.log_info("After notification handler execution")

# Behavior specific to AddPost request
class AddPostLoggingBehavior(PipelineBehavior[AddPost, int]):
def handle(
self,
resolver: Resolver,
target: AddPost,
handle_next: HandleNext[AddPost, int],
) -> int:
logger = resolver.resolve(Logger)
logger.log_info("Before post addition")
response = handle_next(resolver, target)
logger.log_info(f"After post addition: id = {response}")

return response

# Behavior specific to PostAdded notification
class PostAddedLoggingBehavior(PipelineBehavior[PostAdded, None]):
def handle(
self,
resolver: Resolver,
target: PostAdded,
handle_next: HandleNext[PostAdded, None],
) -> None:
logger = resolver.resolve(Logger)
logger.log_info("Before post added handler execution")
handle_next(resolver, target)
logger.log_info(f"After post added handler execution: id = {target.post_id}")
```

### Registering Pipeline Behaviors
Define the factory function for `PipelineBehaviorRegistry`. The order of behavior registration determines the execution sequence - behaviors are executed in the order they are added:

```python
from bazario import PipelineBehaviorRegistry

def build_registry() -> PipelineBehaviorRegistry:
registry = PipelineBehaviorRegistry()
# Behaviors will execute in this order:
# 1. RequestLoggingBehavior
# 2. NotificationLoggingBehavior
# 3. AddPostLoggingBehavior
# 4. PostAddedLoggingBehavior
registry.add_behaviours(Request, RequestLoggingBehaviour())
registry.add_behaviours(Notification, NotificationLoggingBehaviour())
registry.add_behaviours(AddPost, AddPostLoggingBehaviour())
registry.add_behaviours(PostAdded, PostAddedLoggingBehaviour())

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:
```python
def build_registry() -> PipelineBehaviourRegistry:
registry = PipelineBehaviourRegistry()

registry.add_behaviours(Request, RequestLoggingBehaviour())
registry.add_behaviours(
AddPost,
ValidationBehaviour(),
MetricsBehaviour(),
)

return registry

# Execution sequence for AddPost request:
# 1. RequestLoggingBehaviour
# 2. ValidationBehaviour
# 3. MetricsBehaviour
# 4. Actual AddPost handler
```

Configure the IoC container:
```python
def build_container() -> Container:
# ...
main_provider.provide(build_registry)
# Note: The Dispatcher depends on PipelineBehaviourRegistry.
# If you're not using pipeline behaviors, register PipelineBehaviourRegistry directly:
# main_provider.provide(PipelineBehaviourRegistry)
# ...
```

### 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
Loading

0 comments on commit 83421dd

Please sign in to comment.