Skip to content

Commit 03708bb

Browse files
committed
docs: complete extending middlewares section
Signed-off-by: heitorlessa <lessa@amazon.co.uk>
1 parent 2f2eb91 commit 03708bb

File tree

2 files changed

+62
-1
lines changed

2 files changed

+62
-1
lines changed

docs/core/event_handler/api_gateway.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,21 @@ While there isn't anything special on how to use [`try/catch`](https://docs.pyth
539539

540540
#### Extending middlewares
541541

542-
!!! todo "Explain how to create a middleware that accepts configuration with `BaseMiddlewareHandler`"
542+
You can implement `BaseMiddlewareHandler` interface to create middlewares that accept configuration, or perform complex operations (_see [being a good citizen section](#being-a-good-citizen)_).
543+
544+
As a practical example, let's refactor our correlation ID middleware so it accepts a custom HTTP Header to look for.
545+
546+
```python hl_lines="5 11 23 36" title="Authoring class-based middlewares with BaseMiddlewareHandler"
547+
--8<-- "examples/event_handler_rest/src/middleware_extending_middlewares.py"
548+
```
549+
550+
1. You can add any constructor argument like you normally would
551+
2. We implement `handler` just like we [did before](#middleware) with the only exception of the `self` argument, since it's a method.
552+
3. Get response from the next middleware (if any) or from `/todos` route.
553+
4. Register an instance of `CorrelationIdMiddleware`.
554+
555+
!!! note "Class-based **vs** function-based middlewares"
556+
When registering a middleware, we expect a callable in both cases. For class-based middlewares, `BaseMiddlewareHandler` is doing the work of calling your `handler` method with the correct parameters, hence why we expect an instance of it.
543557

544558
#### Being a good citizen
545559

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import requests
2+
3+
from aws_lambda_powertools import Logger
4+
from aws_lambda_powertools.event_handler import APIGatewayRestResolver, Response
5+
from aws_lambda_powertools.event_handler.middlewares import BaseMiddlewareHandler, NextMiddleware
6+
7+
app = APIGatewayRestResolver()
8+
logger = Logger()
9+
10+
11+
class CorrelationIdMiddleware(BaseMiddlewareHandler):
12+
def __init__(self, header: str): # (1)!
13+
"""Extract and inject correlation ID in response
14+
15+
Parameters
16+
----------
17+
header : str
18+
HTTP Header to extract correlation ID
19+
"""
20+
super().__init__()
21+
self.header = header
22+
23+
def handler(self, app: APIGatewayRestResolver, next_middleware: NextMiddleware) -> Response: # (2)!
24+
request_id = app.current_event.request_context.request_id
25+
correlation_id = app.current_event.get_header_value(
26+
name=self.header,
27+
default_value=request_id,
28+
)
29+
30+
response = next_middleware(app) # (3)!
31+
response.headers[self.header] = correlation_id
32+
33+
return response
34+
35+
36+
@app.get("/todos", middlewares=[CorrelationIdMiddleware(header="x-correlation-id")]) # (4)!
37+
def get_todos():
38+
todos: requests.Response = requests.get("https://jsonplaceholder.typicode.com/todos")
39+
todos.raise_for_status()
40+
41+
# for brevity, we'll limit to the first 10 only
42+
return {"todos": todos.json()[:10]}
43+
44+
45+
@logger.inject_lambda_context
46+
def lambda_handler(event, context):
47+
return app.resolve(event, context)

0 commit comments

Comments
 (0)