Skip to content

Commit aa68e40

Browse files
committed
chore: last cleanups
Signed-off-by: heitorlessa <[email protected]>
1 parent d1508c7 commit aa68e40

File tree

5 files changed

+83
-166
lines changed

5 files changed

+83
-166
lines changed

aws_lambda_powertools/event_handler/api_gateway.py

Lines changed: 43 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ def __init__(
206206
cors: bool,
207207
compress: bool,
208208
cache_control: Optional[str],
209-
middlewares: Optional[List[Callable[..., Any]]],
209+
middlewares: Optional[List[Callable[..., Response]]],
210210
):
211211
"""
212212
@@ -225,9 +225,8 @@ def __init__(
225225
Whether or not to enable gzip compression for this route
226226
cache_control: Optional[str]
227227
The cache control header value, example "max-age=3600"
228-
middlewares: Optional[List[Callable[..., Any]]]
229-
The list of route middlewares. These are called in the order they are
230-
provided.
228+
middlewares: Optional[List[Callable[..., Response]]]
229+
The list of route middlewares to be called in order.
231230
"""
232231
self.method = method.upper()
233232
self.rule = rule
@@ -238,9 +237,7 @@ def __init__(
238237
self.cache_control = cache_control
239238
self.middlewares = middlewares or []
240239

241-
"""
242-
_middleware_stack_built is used to ensure the middleware stack is only built once.
243-
"""
240+
# _middleware_stack_built is used to ensure the middleware stack is only built once.
244241
self._middleware_stack_built = False
245242

246243
def __call__(
@@ -258,7 +255,7 @@ def __call__(
258255
----------
259256
router_middlewares: List[Callable]
260257
The list of Router Middlewares (assigned to ALL routes)
261-
app: Callable
258+
app: "ApiGatewayResolver"
262259
The ApiGatewayResolver instance to pass into the middleware stack
263260
route_arguments: Dict[str, str]
264261
The route arguments to pass to the app function (extracted from the Api Gateway
@@ -267,13 +264,11 @@ def __call__(
267264
Returns
268265
-------
269266
Union[Dict, Tuple, Response]
270-
Returns an API Response object in ALL cases, excepting when the original API route
271-
handler is called which may also return a Dict or Tuple response.
267+
API Response object in ALL cases, except when the original API route
268+
handler is called which may also return a Dict, Tuple, or Response.
272269
"""
273270

274-
# Check self._middleware_stack_built to ensure the middleware stack is only built once.
275-
# This will save CPU time when an API route is processed multiple times.
276-
#
271+
# Save CPU cycles by building middleware stack once
277272
if not self._middleware_stack_built:
278273
self._build_middleware_stack(router_middlewares=router_middlewares)
279274

@@ -312,14 +307,16 @@ def _build_middleware_stack(self, router_middlewares: List[Callable[..., Any]])
312307
middleware handlers is applied in the order of being added to the handler.
313308
"""
314309
all_middlewares = router_middlewares + self.middlewares
310+
logger.debug(f"Building middleware stack: {all_middlewares}")
315311

316312
# IMPORTANT:
317313
# this must be the last middleware in the stack (tech debt for backward
318-
# compatability purposes)
314+
# compatibility purposes)
319315
#
320-
# This adapter will call the registered API passing only the expected route arguments extracted from the path
316+
# This adapter will:
317+
# 1. Call the registered API passing only the expected route arguments extracted from the path
321318
# and not the middleware.
322-
# This adapter will adapt the response type of the route handler (Union[Dict, Tuple, Response])
319+
# 2. Adapt the response type of the route handler (Union[Dict, Tuple, Response])
323320
# and normalise into a Response object so middleware will always have a constant signature
324321
all_middlewares.append(_registered_api_adapter)
325322

@@ -450,31 +447,42 @@ def route(
450447

451448
def use(self, middlewares: List[Callable[..., Response]]) -> None:
452449
"""
453-
Add a list of middlewares to the global router middleware list
450+
Add one or more global middlewares that run before/after route specific middleware.
454451
455-
These middlewares will be called in insertion order and
456-
before any middleware registered at the route level.
452+
NOTE: Middlewares are called in insertion order.
453+
454+
Parameters
455+
----------
456+
middlewares: List[Callable[..., Response]]
457+
List of global middlewares to be used
458+
459+
Examples
460+
--------
457461
458-
Example
459-
-------
460462
Add middlewares to be used for every request processed by the Router.
461463
462-
```
463-
my_custom_middleware = new CustomMiddleware()
464+
```python
465+
from aws_lambda_powertools import Logger
466+
from aws_lambda_powertools.event_handler import APIGatewayRestResolver, Response
467+
from aws_lambda_powertools.event_handler.middlewares import NextMiddleware
464468
465-
app.use([my_custom_middleware])
469+
logger = Logger()
470+
app = APIGatewayRestResolver()
466471
467-
```
472+
def log_request_response(app: APIGatewayRestResolver, next_middleware: NextMiddleware) -> Response:
473+
logger.info("Incoming request", path=app.current_event.path, request=app.current_event.raw_event)
468474
469-
Parameters
470-
----------
471-
middlewares - List of middlewares to be used
475+
result = next_middleware(app)
476+
logger.info("Response received", response=result.__dict__)
472477
473-
Returns
474-
-------
475-
None
478+
return result
476479
480+
app.use(middlewares=[log_request_response])
477481
482+
483+
def lambda_handler(event, context):
484+
return app.resolve(event, context)
485+
```
478486
"""
479487
self._router_middlewares = self._router_middlewares + middlewares
480488

@@ -646,14 +654,14 @@ def lambda_handler(event, context):
646654
def _push_processed_stack_frame(self, frame: str):
647655
"""
648656
Add Current Middleware to the Middleware Stack Frames
649-
The stack frames will be used when excpetions are thrown and Powertools
657+
The stack frames will be used when exceptions are thrown and Powertools
650658
debug is enabled by developers.
651659
"""
652660
self.processed_stack_frames.append(frame)
653661

654662
def _reset_processed_stack(self):
655663
"""Reset the Processed Stack Frames"""
656-
self.processed_stack_frames = []
664+
self.processed_stack_frames.clear()
657665

658666
def append_context(self, **additional_context):
659667
"""Append key=value data as routing context"""
@@ -832,6 +840,7 @@ def __init__(
832840
self._debug = self._has_debug(debug)
833841
self._strip_prefixes = strip_prefixes
834842
self.context: Dict = {} # early init as customers might add context before event resolution
843+
self.processed_stack_frames = []
835844

836845
# Allow for a custom serializer or a concise json serialization
837846
self._serializer = serializer or partial(json.dumps, separators=(",", ":"), cls=Encoder)
@@ -1005,8 +1014,7 @@ def _resolve(self) -> ResponseBuilder:
10051014
if match_results:
10061015
logger.debug("Found a registered route. Calling function")
10071016
# Add matched Route reference into the Resolver context
1008-
self.append_context(_route=route)
1009-
self.append_context(_path=path)
1017+
self.append_context(_route=route, _path=path)
10101018

10111019
return self._call_route(route, match_results.groupdict()) # pass fn args
10121020

aws_lambda_powertools/event_handler/middlewares/base.py

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -18,64 +18,64 @@ def __name__(self) -> str: # noqa A003
1818

1919

2020
class BaseMiddlewareHandler(Generic[EventHandlerInstance], ABC):
21-
"""
22-
Base class for Middleware Handlers
21+
"""Base implementation for Middlewares to run code before and after in a chain.
22+
2323
2424
This is the middleware handler function where middleware logic is implemented.
25-
Here you have the option to execute code before and after the next handler in the
26-
middleware chain is called. The next middleware handler is represented by `next_middleware`.
25+
The next middleware handler is represented by `next_middleware`, returning a Response object.
26+
27+
Examples
28+
--------
2729
30+
**Correlation ID Middleware**
2831
2932
```python
33+
import requests
3034
31-
# Place code here for actions BEFORE the next middleware handler is called
32-
# or optionally raise an exception to short-circuit the middleware execution chain
35+
from aws_lambda_powertools import Logger
36+
from aws_lambda_powertools.event_handler import APIGatewayRestResolver, Response
37+
from aws_lambda_powertools.event_handler.middlewares import BaseMiddlewareHandler, NextMiddleware
3338
34-
# Get the response from the NEXT middleware handler (optionally injecting custom
35-
# arguments into the next_middleware call)
36-
result: Response = next_middleware(app, my_custom_arg="handled")
39+
app = APIGatewayRestResolver()
40+
logger = Logger()
3741
38-
# Place code here for actions AFTER the next middleware handler is called
3942
40-
return result
41-
```
43+
class CorrelationIdMiddleware(BaseMiddlewareHandler):
44+
def __init__(self, header: str):
45+
super().__init__()
46+
self.header = header
4247
43-
To implement ERROR style middleware wrap the call to `next_middleware` in a `try..except`
44-
block - you can also catch specific types of errors this way so your middleware only handles
45-
specific types of exceptions.
48+
def handler(self, app: APIGatewayRestResolver, next_middleware: NextMiddleware) -> Response:
49+
# BEFORE logic
50+
request_id = app.current_event.request_context.request_id
51+
correlation_id = app.current_event.get_header_value(
52+
name=self.header,
53+
default_value=request_id,
54+
)
4655
47-
for example:
56+
# Call next middleware or route handler ('/todos')
57+
response = next_middleware(app)
4858
49-
```python
59+
# AFTER logic
60+
response.headers[self.header] = correlation_id
5061
51-
try:
52-
result: Response = next_middleware(app, my_custom_arg="handled")
53-
except MyCustomValidationException as e:
54-
# Make sure we send back a 400 response for any Custom Validation Exceptions.
55-
result.status_code = 400
56-
result.body = {"message": "Failed validation"}
57-
logger.exception(f"Failed validation when handling route: {app.current_event.path}")
62+
return response
5863
59-
return result
60-
```
6164
62-
To short-circuit the middleware execution chain you can either raise an exception to cause
63-
the function call stack to unwind naturally OR you can simple not call the `next_middleware`
64-
handler to get the response from the next middleware handler in the chain.
65+
@app.get("/todos", middlewares=[CorrelationIdMiddleware(header="x-correlation-id")])
66+
def get_todos():
67+
todos: requests.Response = requests.get("https://jsonplaceholder.typicode.com/todos")
68+
todos.raise_for_status()
6569
66-
for example:
67-
If you wanted to ensure API callers cannot call a DELETE verb on your API (regardless of defined routes)
68-
you could do so with the following middleware implementation.
70+
# for brevity, we'll limit to the first 10 only
71+
return {"todos": todos.json()[:10]}
6972
70-
```python
71-
# If invalid http_method is used - return a 405 error
72-
# and return early to short-circuit the middleware execution chain
73-
if app.current_event.http_method == "DELETE":
74-
return Response(status_code=405, body={"message": "DELETE verb not allowed"})
7573
74+
@logger.inject_lambda_context
75+
def lambda_handler(event, context):
76+
return app.resolve(event, context)
7677
77-
# Call the next middleware in the chain (needed for when condition above is valid)
78-
return next_middleware(app)
78+
```
7979
8080
"""
8181

@@ -111,7 +111,7 @@ def __call__(self, app: EventHandlerInstance, next_middleware: NextMiddleware) -
111111
----------
112112
app: ApiGatewayResolver
113113
An instance of an Event Handler that implements ApiGatewayResolver
114-
next_middleware: Callable[..., Any]
114+
next_middleware: NextMiddleware
115115
The next middleware handler in the chain
116116
117117
Returns

examples/event_handler_rest/src/all_routes_middleware.py

Lines changed: 0 additions & 31 deletions
This file was deleted.

examples/event_handler_rest/src/custom_middlewares.py

Lines changed: 0 additions & 31 deletions
This file was deleted.

examples/event_handler_rest/src/route_middleware.py

Lines changed: 0 additions & 29 deletions
This file was deleted.

0 commit comments

Comments
 (0)