0
# Decorators and Routing
1
2
The decorator system provides a unified interface for registering handler functions across different transport types (broker, HTTP, periodic). The `enroute` decorator system automatically handles routing, middleware integration, and request/response processing.
3
4
## Capabilities
5
6
### Main Decorator Interface
7
8
The `enroute` object provides access to all decorator types through a hierarchical interface.
9
10
```python { .api }
11
enroute: Enroute
12
13
class Enroute:
14
broker: BrokerEnroute
15
rest: RestEnroute
16
periodic: PeriodicEnroute
17
```
18
19
### Broker Decorators
20
21
Decorators for message broker handlers supporting commands, queries, and events.
22
23
```python { .api }
24
class BrokerEnroute:
25
command: type[BrokerCommandEnrouteDecorator]
26
query: type[BrokerQueryEnrouteDecorator]
27
event: type[BrokerEventEnrouteDecorator]
28
29
class BrokerCommandEnrouteDecorator:
30
def __init__(self, topic: str, **kwargs): ...
31
topic: str
32
KIND: EnrouteDecoratorKind = EnrouteDecoratorKind.Command
33
34
class BrokerQueryEnrouteDecorator:
35
def __init__(self, topic: str, **kwargs): ...
36
topic: str
37
KIND: EnrouteDecoratorKind = EnrouteDecoratorKind.Query
38
39
class BrokerEventEnrouteDecorator:
40
def __init__(self, topic: str, **kwargs): ...
41
topic: str
42
KIND: EnrouteDecoratorKind = EnrouteDecoratorKind.Event
43
```
44
45
**Usage Examples:**
46
47
```python
48
@enroute.broker.command("user.create")
49
async def create_user(request: Request) -> Response:
50
user_data = await request.content()
51
return Response({"id": "123", "status": "created"})
52
53
@enroute.broker.query("user.get")
54
async def get_user(request: Request) -> Response:
55
user_id = await request.content()
56
return Response({"id": user_id, "name": "John Doe"})
57
58
@enroute.broker.event("user.created")
59
async def handle_user_created(request: Request) -> Response:
60
event_data = await request.content()
61
# Handle event processing
62
return Response({"processed": True})
63
```
64
65
### REST Decorators
66
67
Decorators for HTTP REST endpoint handlers supporting commands and queries.
68
69
```python { .api }
70
class RestEnroute:
71
command: type[RestCommandEnrouteDecorator]
72
query: type[RestQueryEnrouteDecorator]
73
74
class RestCommandEnrouteDecorator:
75
def __init__(self, path: str, method: str = "POST", **kwargs): ...
76
path: str
77
method: str
78
KIND: EnrouteDecoratorKind = EnrouteDecoratorKind.Command
79
80
class RestQueryEnrouteDecorator:
81
def __init__(self, path: str, method: str = "GET", **kwargs): ...
82
path: str
83
method: str
84
KIND: EnrouteDecoratorKind = EnrouteDecoratorKind.Query
85
```
86
87
**Usage Examples:**
88
89
```python
90
@enroute.rest.command("/users", method="POST")
91
async def create_user_http(request: Request) -> Response:
92
user_data = await request.content()
93
return Response({"id": "123", "status": "created"})
94
95
@enroute.rest.query("/users/{user_id}", method="GET")
96
async def get_user_http(request: Request) -> Response:
97
params = await request.params()
98
user_id = params["user_id"]
99
return Response({"id": user_id, "name": "John Doe"})
100
101
@enroute.rest.command("/users/{user_id}", method="PUT")
102
async def update_user(request: Request) -> Response:
103
params = await request.params()
104
user_data = await request.content()
105
return Response({"id": params["user_id"], "status": "updated"})
106
```
107
108
### Periodic Decorators
109
110
Decorators for scheduled task handlers using cron expressions.
111
112
```python { .api }
113
class PeriodicEnroute:
114
event: type[PeriodicEventEnrouteDecorator]
115
116
class PeriodicEventEnrouteDecorator:
117
def __init__(self, crontab: Union[str, CronTab], **kwargs): ...
118
crontab: CronTab
119
KIND: EnrouteDecoratorKind = EnrouteDecoratorKind.Event
120
```
121
122
**Usage Examples:**
123
124
```python
125
@enroute.periodic.event("0 */5 * * * *") # Every 5 minutes
126
async def cleanup_task(request: Request) -> Response:
127
# Periodic cleanup logic
128
return Response({"status": "cleanup_completed"})
129
130
@enroute.periodic.event("0 0 * * *") # Daily at midnight
131
async def daily_report(request: Request) -> Response:
132
# Generate daily reports
133
return Response({"report": "generated"})
134
135
# Using CronTab object
136
from minos.networks import CronTab
137
cron = CronTab("0 30 9 * * MON-FRI") # Weekdays at 9:30 AM
138
139
@enroute.periodic.event(cron)
140
async def business_hours_task(request: Request) -> Response:
141
return Response({"status": "executed"})
142
```
143
144
### Handler Metadata and Wrappers
145
146
Classes for managing handler function metadata and execution wrappers.
147
148
```python { .api }
149
class HandlerMeta:
150
def __init__(self, func: Handler, decorators: Optional[set[EnrouteDecorator]] = None, checkers: Optional[set[CheckerMeta]] = None): ...
151
func: Handler
152
decorators: set[EnrouteDecorator]
153
checkers: set[CheckerMeta]
154
wrapper: HandlerWrapper
155
check: type[CheckDecorator]
156
def add_decorator(self, decorator: EnrouteDecorator) -> None: ...
157
158
class HandlerWrapper:
159
"""Wrapper for handler functions with decorator metadata"""
160
161
class CheckerMeta:
162
def __init__(self, func: Checker, max_attempts: int, delay: float): ...
163
func: Checker
164
max_attempts: int
165
delay: float
166
wrapper: CheckerWrapper
167
@staticmethod
168
async def run_async(metas: set[CheckerMeta], *args, **kwargs) -> None: ...
169
@staticmethod
170
def run_sync(metas: set[CheckerMeta], *args, **kwargs) -> bool: ...
171
172
class CheckDecorator:
173
def __init__(self, handler_meta: HandlerMeta, max_attempts: int = 10, delay: Union[float, timedelta] = 0.1): ...
174
max_attempts: int
175
delay: float
176
def __call__(self, func: Union[CheckerWrapper, Checker]) -> CheckerWrapper: ...
177
```
178
179
### Route Collection and Factories
180
181
Utilities for discovering and organizing decorated handlers.
182
183
```python { .api }
184
class EnrouteCollector:
185
def __init__(self, decorated: Any, config: Optional[Config] = None): ...
186
decorated: Any
187
config: Optional[Config]
188
def get_rest_command_query(self) -> dict[str, set[RestEnrouteDecorator]]: ...
189
def get_broker_command_query_event(self) -> dict[str, set[BrokerEnrouteDecorator]]: ...
190
def get_broker_command_query(self) -> dict[str, set[BrokerEnrouteDecorator]]: ...
191
def get_broker_event(self) -> dict[str, set[BrokerEnrouteDecorator]]: ...
192
def get_periodic_event(self) -> dict[str, set[PeriodicEventEnrouteDecorator]]: ...
193
def get_all(self) -> dict[str, set[EnrouteDecorator]]: ...
194
195
class EnrouteFactory:
196
def __init__(self, *classes: Union[str, type], middleware: Optional[Union[str, Callable, list]] = None): ...
197
classes: tuple
198
middleware: list
199
def get_rest_command_query(self, **kwargs) -> dict[RestEnrouteDecorator, Handler]: ...
200
def get_broker_command_query_event(self, **kwargs) -> dict[BrokerEnrouteDecorator, Handler]: ...
201
def get_broker_command_query(self, **kwargs) -> dict[BrokerEnrouteDecorator, Handler]: ...
202
def get_broker_event(self, **kwargs) -> dict[BrokerEnrouteDecorator, Handler]: ...
203
def get_periodic_event(self, **kwargs) -> dict[PeriodicEnrouteDecorator, Handler]: ...
204
def get_all(self, **kwargs) -> dict[EnrouteDecorator, Handler]: ...
205
```
206
207
### Decorator Types and Constants
208
209
```python { .api }
210
from typing import Callable, Union, Optional, Awaitable
211
from enum import Enum, auto
212
213
Handler = Callable[[Request], Union[Optional[Response], Awaitable[Optional[Response]]]]
214
Checker = Callable[[Request], Union[Optional[bool], Awaitable[Optional[bool]]]]
215
216
class EnrouteDecoratorKind(Enum):
217
Command = auto()
218
Query = auto()
219
Event = auto()
220
221
@property
222
def pre_fn_name(self) -> str:
223
"""Returns pre-execution function name mapping"""
224
225
@property
226
def post_fn_name(self) -> str:
227
"""Returns post-execution function name mapping"""
228
```
229
230
### Handler and Checker System
231
232
Core abstractions for request processing and validation with metadata support.
233
234
```python { .api }
235
class Handler:
236
"""Base class for handling decorated function execution"""
237
def __init__(self, fn: Callable, decorators: list[EnrouteDecorator] = None): ...
238
fn: Callable
239
decorators: list[EnrouteDecorator]
240
241
class HandlerMeta:
242
"""Metadata container for handler information"""
243
def __init__(self, fn: Callable): ...
244
245
class HandlerWrapper:
246
"""Wrapper that provides handler execution context"""
247
def __init__(self, handler: Handler): ...
248
async def __call__(self, request: Request) -> Response: ...
249
250
class Checker:
251
"""Base class for request validation logic"""
252
def __init__(self, fn: Callable): ...
253
fn: Callable
254
255
class CheckerMeta:
256
"""Metadata container for checker information"""
257
def __init__(self, fn: Callable): ...
258
259
class CheckerWrapper:
260
"""Wrapper that provides checker execution context"""
261
def __init__(self, checker: Checker): ...
262
async def __call__(self, request: Request) -> bool: ...
263
264
class CheckDecorator:
265
"""Decorator for adding validation checks to handlers"""
266
def __init__(self, max_attempts: int = 1, delay: float = 0.0): ...
267
max_attempts: int
268
delay: float
269
```
270
271
**Usage Examples:**
272
273
```python
274
from minos.networks import Handler, Checker, CheckDecorator
275
276
# Custom handler with metadata
277
handler = Handler(my_function, decorators=[decorator1, decorator2])
278
wrapped = HandlerWrapper(handler)
279
280
# Custom checker for validation
281
checker = Checker(my_validation_function)
282
wrapped_checker = CheckerWrapper(checker)
283
284
# Using check decorator
285
@CheckDecorator(max_attempts=3, delay=0.5)
286
async def validate_input(request: Request) -> bool:
287
return True # validation logic
288
```
289
290
## Advanced Usage
291
292
### Adding Pre/Post Execution Checks
293
294
```python
295
class UserService:
296
@enroute.broker.command("user.create")
297
async def create_user(self, request: Request) -> Response:
298
# Handler implementation
299
pass
300
301
# Add checker with retry logic
302
@create_user.check(max_attempts=3, delay=0.5)
303
async def validate_user_data(self, request: Request) -> bool:
304
user_data = await request.content()
305
return "email" in user_data and "name" in user_data
306
```
307
308
### Middleware Integration
309
310
```python
311
from minos.networks import EnrouteFactory
312
313
# Create factory with middleware
314
factory = EnrouteFactory(
315
UserService,
316
OrderService,
317
middleware=["auth_middleware", "logging_middleware"]
318
)
319
320
# Get handlers with middleware applied
321
handlers = factory.get_all()
322
```
323
324
### Service Class Organization
325
326
```python
327
class UserService:
328
@enroute.broker.command("user.create")
329
async def create_user(self, request: Request) -> Response:
330
return Response({"status": "created"})
331
332
@enroute.broker.query("user.get")
333
async def get_user(self, request: Request) -> Response:
334
return Response({"user": "data"})
335
336
@enroute.rest.command("/users", method="POST")
337
async def create_user_rest(self, request: Request) -> Response:
338
return Response({"status": "created"})
339
340
@enroute.rest.query("/users/{user_id}", method="GET")
341
async def get_user_rest(self, request: Request) -> Response:
342
return Response({"user": "data"})
343
344
@enroute.periodic.event("0 0 * * *")
345
async def daily_cleanup(self, request: Request) -> Response:
346
return Response({"status": "cleaned"})
347
```