-
Notifications
You must be signed in to change notification settings - Fork 403
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(event_handler): improved support for headers and cookies in v2 #1455
feat(event_handler): improved support for headers and cookies in v2 #1455
Conversation
Thank you so much @rubenfonseca. Two QQ before I start reviewing the implementation: 1. Can customers add multiple value headers in |
|
b380779
to
1c653de
Compare
For some reason I can't run tests locally because it fails on apigw v2 alpha import. I've noticed CI didn't run (to confirm if it's on my laptop only) because it's the new The PR is just fantastic. The only gut feeling I'm having is the UX of only supporting a list of values for headers - I'd like to run some tests locally to remind myself whether |
Asked on Discord, and two customers prefer values always being a list regardless - please disregard this comment. I'll merge on Monday - just need to double check docs on event handler code snippets output |
As we discussed in the standup, we'll go with
|
Signed-off-by: heitorlessa <[email protected]>
Signed-off-by: heitorlessa <[email protected]>
Signed-off-by: heitorlessa <[email protected]>
Ready to review. |
we can cleanup the leftovers from peer review on adding a more realistic cookie, and use |
…1455) Co-authored-by: Heitor Lessa <[email protected]>
…ws-powertools#1455) Co-authored-by: Heitor Lessa <[email protected]>
…ws-powertools#1455) Co-authored-by: Heitor Lessa <[email protected]>
…ws-powertools#1455) Co-authored-by: Heitor Lessa <[email protected]>
…ws-powertools#1455) Co-authored-by: Heitor Lessa <[email protected]>
…1455) Co-authored-by: Heitor Lessa <[email protected]>
…1455) Co-authored-by: Heitor Lessa <[email protected]>
if isinstance(values, str): | ||
payload["headers"][key] = values | ||
else: | ||
if len(values) > 1: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@heitorlessa I'm seeing TypeError: object of type 'NoneType' has no len()
when I have the following header set:
'Access-Control-Allow-Origin': None
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jasmarc could you create a bug report issue on this please?
We can make a patch release as soon as we reproduce it.
Thanks a lot!!!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
with my laptop now
While we await for a bug report and a fix by EOD for headers with None
value, you can safely use an empty string instead of None
.
Because we provide native support for CORS in Event Handler, you can do as follows:
Test URL: https://xwgyz6mo2m.execute-api.eu-west-1.amazonaws.com/Prod/hello/
from aws_lambda_powertools.event_handler import APIGatewayRestResolver, CORSConfig
cors = CORSConfig(allow_origin="") # Create CORS configuration
app = APIGatewayRestResolver(cors=cors) # Ensure CORS is properly configured for all routes
@app.get("/hello")
def hello():
return {"hello": "world"}
def lambda_handler(event, context):
return app.resolve(event, context)
If your intent is to set an explicit null
in the Allow-Origin...
W3C doesn't recommend having an Allow Origin explicitly set to null
due to potential data leak, since data:
and file:
schemes can accessnull
origins - that's not the case with an empty Allow Origin (''
). Unless I'm misunderstanding both your intent (bug report helps!) or W3C docs.
With an explicit null
import json
from aws_lambda_powertools.event_handler import (
APIGatewayRestResolver,
CORSConfig,
Response,
)
# Not recommended due to data: and file: schemes also using `null` origin
# https://w3c.github.io/webappsec-cors-for-developers/#avoid-returning-access-control-allow-origin-null
cors = CORSConfig(allow_origin="null")
app = APIGatewayRestResolver(cors=cors)
# https://xwgyz6mo2m.execute-api.eu-west-1.amazonaws.com/Prod/hello/
@app.get("/hello")
def hello():
return {"hello": "world"}
# chore: verify API Gateway REST Lambda integration behaviour with `None`
# API Gateway REST serializes`None` as an empty string (just like `null` in JS)
# need proper E2E to validate behaviour for API Gateway HTTP (v2), ALB, and Function URL resolvers
# https://xwgyz6mo2m.execute-api.eu-west-1.amazonaws.com/Prod/none/
@app.get("/none")
def hello():
headers = {"X-Empty": None, "X-Null": "null"}
response = {"hello": "world"}
return Response(body=json.dumps(response), headers=headers, status_code=200)
def lambda_handler(event, context):
return app.resolve(event, context)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@leandrodamascena when you're back online, feel free to create a bug report if we don't hear from the customer within an hour. Leaving the tests and my endpoint above to save you from setting it all up besides E2E.
tests/functional/test_headers_serializer.py
These tests reproduce the issue. What needs to be done is an E2E for each resolver to confirm whether the final value becomes ''
or fails (ALB is always the odd one) - this needs to be documented too later.
def test_http_api_headers_serializer_with_null_values():
serializer = HttpApiHeadersSerializer()
payload = serializer.serialize(headers={"Foo": None}, cookies=[])
assert payload == {"headers": {}, "cookies": []}
def test_multi_value_headers_serializer_with_null_values():
serializer = MultiValueHeadersSerializer()
payload = serializer.serialize(headers={"Foo": None}, cookies=[])
assert payload == {"headers": {}, "cookies": []}
def test_single_value_headers_serializer_with_null_values():
serializer = SingleValueHeadersSerializer()
payload = serializer.serialize(headers={"Foo": None}, cookies=[])
assert payload["headers"] == {}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @heitorlessa sorry for the delay. Yes, I worked around it and I did also notice that it was not recommended, so I almost hesitated to bring it up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have filed #1791
Issue number: #1192, #1450
Summary
Changes
This change adds support for transparently serialize headers and cookies when using the
Response
object. Powertools will pick the correct payload format depending on the type of input event, and serialize headers and cookies accordingly.User experience
Before this change, setting cookies was done manually:
This had multiple problems:
multiValueHeaders
key in the response payload.After this change, users can set headers and cookies freely (single or multiple), and Powertools will serialize them correctly according to the type of input event:
Existing code will still work because we model header values as a union
Union[str, List[str]]
.API Gateway HTTP API integration output:
ALB Integration output:
This improves the usability and hides the implementation differences across the different integrations.
Caveat
There is a scenario where using the default ALB integration configuration (
multiValueHeaders
are disabled) while setting multiple cookies would fail. When we detect that scenario, a warning is printed and the last cookie/header is set.Checklist
If your change doesn't seem to apply, please leave them unchecked.
Is this a breaking change?
Yes, two breaking changes are introduced:
headers
parameter in the Response object changed fromDict
to the more explicitDict[str, List[str]]
headers
andcookies
on the payload. But on other integrations (REST API, ALB) we will seemultiValueHeaders
with aDict[str, List[str]]
type. This could break existing customer tests.RFC issue number:
Checklist:
Acknowledgment
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.
Disclaimer: We value your time and bandwidth. As such, any pull requests created on non-triaged issues might not be successful.
View rendered docs/core/event_handler/api_gateway.md