forked from aws-powertools/powertools-lambda-python
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(event_handler): improved support for headers and cookies in v2 (a…
…ws-powertools#1455) Co-authored-by: Heitor Lessa <[email protected]>
- Loading branch information
Showing
33 changed files
with
1,323 additions
and
886 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -305,5 +305,8 @@ site/ | |
!404.html | ||
!docs/overrides/*.html | ||
|
||
# CDK | ||
.cdk | ||
|
||
!.github/workflows/lib | ||
examples/**/sam/.aws-sam |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,15 @@ | ||
# -*- coding: utf-8 -*- | ||
|
||
"""Top-level package for Lambda Python Powertools.""" | ||
|
||
from pathlib import Path | ||
|
||
"""Top-level package for Lambda Python Powertools.""" | ||
from .logging import Logger # noqa: F401 | ||
from .metrics import Metrics, single_metric # noqa: F401 | ||
from .package_logger import set_package_logger_handler | ||
from .tracing import Tracer # noqa: F401 | ||
|
||
__author__ = """Amazon Web Services""" | ||
|
||
PACKAGE_PATH = Path(__file__).parent | ||
|
||
set_package_logger_handler() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
import warnings | ||
from collections import defaultdict | ||
from typing import Any, Dict, List, Union | ||
|
||
|
||
class BaseHeadersSerializer: | ||
""" | ||
Helper class to correctly serialize headers and cookies for Amazon API Gateway, | ||
ALB and Lambda Function URL response payload. | ||
""" | ||
|
||
def serialize(self, headers: Dict[str, Union[str, List[str]]], cookies: List[str]) -> Dict[str, Any]: | ||
""" | ||
Serializes headers and cookies according to the request type. | ||
Returns a dict that can be merged with the response payload. | ||
Parameters | ||
---------- | ||
headers: Dict[str, List[str]] | ||
A dictionary of headers to set in the response | ||
cookies: List[str] | ||
A list of cookies to set in the response | ||
""" | ||
raise NotImplementedError() | ||
|
||
|
||
class HttpApiHeadersSerializer(BaseHeadersSerializer): | ||
def serialize(self, headers: Dict[str, Union[str, List[str]]], cookies: List[str]) -> Dict[str, Any]: | ||
""" | ||
When using HTTP APIs or LambdaFunctionURLs, everything is taken care automatically for us. | ||
We can directly assign a list of cookies and a dict of headers to the response payload, and the | ||
runtime will automatically serialize them correctly on the output. | ||
https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html#http-api-develop-integrations-lambda.proxy-format | ||
https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html#http-api-develop-integrations-lambda.response | ||
""" | ||
|
||
# Format 2.0 doesn't have multiValueHeaders or multiValueQueryStringParameters fields. | ||
# Duplicate headers are combined with commas and included in the headers field. | ||
combined_headers: Dict[str, str] = {} | ||
for key, values in headers.items(): | ||
if isinstance(values, str): | ||
combined_headers[key] = values | ||
else: | ||
combined_headers[key] = ", ".join(values) | ||
|
||
return {"headers": combined_headers, "cookies": cookies} | ||
|
||
|
||
class MultiValueHeadersSerializer(BaseHeadersSerializer): | ||
def serialize(self, headers: Dict[str, Union[str, List[str]]], cookies: List[str]) -> Dict[str, Any]: | ||
""" | ||
When using REST APIs, headers can be encoded using the `multiValueHeaders` key on the response. | ||
This is also the case when using an ALB integration with the `multiValueHeaders` option enabled. | ||
The solution covers headers with just one key or multiple keys. | ||
https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-output-format | ||
https://docs.aws.amazon.com/elasticloadbalancing/latest/application/lambda-functions.html#multi-value-headers-response | ||
""" | ||
payload: Dict[str, List[str]] = defaultdict(list) | ||
|
||
for key, values in headers.items(): | ||
if isinstance(values, str): | ||
payload[key].append(values) | ||
else: | ||
for value in values: | ||
payload[key].append(value) | ||
|
||
if cookies: | ||
payload.setdefault("Set-Cookie", []) | ||
for cookie in cookies: | ||
payload["Set-Cookie"].append(cookie) | ||
|
||
return {"multiValueHeaders": payload} | ||
|
||
|
||
class SingleValueHeadersSerializer(BaseHeadersSerializer): | ||
def serialize(self, headers: Dict[str, Union[str, List[str]]], cookies: List[str]) -> Dict[str, Any]: | ||
""" | ||
The ALB integration has `multiValueHeaders` disabled by default. | ||
If we try to set multiple headers with the same key, or more than one cookie, print a warning. | ||
https://docs.aws.amazon.com/elasticloadbalancing/latest/application/lambda-functions.html#respond-to-load-balancer | ||
""" | ||
payload: Dict[str, Dict[str, str]] = {} | ||
payload.setdefault("headers", {}) | ||
|
||
if cookies: | ||
if len(cookies) > 1: | ||
warnings.warn( | ||
"Can't encode more than one cookie in the response. Sending the last cookie only. " | ||
"Did you enable multiValueHeaders on the ALB Target Group?" | ||
) | ||
|
||
# We can only send one cookie, send the last one | ||
payload["headers"]["Set-Cookie"] = cookies[-1] | ||
|
||
for key, values in headers.items(): | ||
if isinstance(values, str): | ||
payload["headers"][key] = values | ||
else: | ||
if len(values) > 1: | ||
warnings.warn( | ||
f"Can't encode more than one header value for the same key ('{key}') in the response. " | ||
"Did you enable multiValueHeaders on the ALB Target Group?" | ||
) | ||
|
||
# We can only set one header per key, send the last one | ||
payload["headers"][key] = values[-1] | ||
|
||
return payload |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
--- | ||
title: Upgrade guide | ||
description: Guide to update between major Powertools versions | ||
--- | ||
|
||
<!-- markdownlint-disable MD043 --> | ||
|
||
## Migrate to v2 from v1 | ||
|
||
The transition from Powertools for Python v1 to v2 is as painless as possible, as we aimed for minimal breaking changes. | ||
Changes at a glance: | ||
|
||
* The API for **event handler's `Response`** has minor changes to support multi value headers and cookies. | ||
|
||
???+ important | ||
Powertools for Python v2 drops suport for Python 3.6, following the Python 3.6 End-Of-Life (EOL) reached on December 23, 2021. | ||
|
||
### Initial Steps | ||
|
||
Before you start, we suggest making a copy of your current working project or create a new branch with git. | ||
|
||
1. **Upgrade** Python to at least v3.7 | ||
|
||
2. **Ensure** you have the latest `aws-lambda-powertools` | ||
|
||
```bash | ||
pip install aws-lambda-powertools -U | ||
``` | ||
|
||
3. **Review** the following sections to confirm whether they affect your code | ||
|
||
## Event Handler Response (headers and cookies) | ||
|
||
The `Response` class of the event handler utility changed slightly: | ||
|
||
1. The `headers` parameter now expects either a value or list of values per header (type `Union[str, Dict[str, List[str]]]`) | ||
2. We introduced a new `cookies` parameter (type `List[str]`) | ||
???+ note | ||
Code that set headers as `Dict[str, str]` will still work unchanged. | ||
```python hl_lines="6 12 13" | ||
@app.get("/todos") | ||
def get_todos(): | ||
# Before | ||
return Response( | ||
# ... | ||
headers={"Content-Type": "text/plain"} | ||
) | ||
# After | ||
return Response( | ||
# ... | ||
headers={"Content-Type": ["text/plain"]}, | ||
cookies=["CookieName=CookieValue"] | ||
) | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
6 changes: 3 additions & 3 deletions
6
examples/event_handler_rest/src/compressing_responses_output.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.