Skip to content

Commit aca525c

Browse files
committed
feat(event_handlers): add support for Lambda Function URL
1 parent a8b3f48 commit aca525c

File tree

6 files changed

+90
-1
lines changed

6 files changed

+90
-1
lines changed

aws_lambda_powertools/event_handler/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
Response,
1212
)
1313
from .appsync import AppSyncResolver
14+
from .lambda_function_url import LambdaFunctionUrlResolver
1415

1516
__all__ = [
1617
"AppSyncResolver",
@@ -19,5 +20,6 @@
1920
"ALBResolver",
2021
"ApiGatewayResolver",
2122
"CORSConfig",
23+
"LambdaFunctionUrlResolver",
2224
"Response",
2325
]

aws_lambda_powertools/event_handler/api_gateway.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,12 @@
1717
from aws_lambda_powertools.shared import constants
1818
from aws_lambda_powertools.shared.functions import resolve_truthy_env_var_choice
1919
from aws_lambda_powertools.shared.json_encoder import Encoder
20-
from aws_lambda_powertools.utilities.data_classes import ALBEvent, APIGatewayProxyEvent, APIGatewayProxyEventV2
20+
from aws_lambda_powertools.utilities.data_classes import (
21+
ALBEvent,
22+
APIGatewayProxyEvent,
23+
APIGatewayProxyEventV2,
24+
LambdaFunctionUrlEvent,
25+
)
2126
from aws_lambda_powertools.utilities.data_classes.common import BaseProxyEvent
2227
from aws_lambda_powertools.utilities.typing import LambdaContext
2328

@@ -36,6 +41,7 @@ class ProxyEventType(Enum):
3641
APIGatewayProxyEvent = "APIGatewayProxyEvent"
3742
APIGatewayProxyEventV2 = "APIGatewayProxyEventV2"
3843
ALBEvent = "ALBEvent"
44+
LambdaFunctionUrlEvent = "LambdaFunctionUrlEvent"
3945

4046

4147
class CORSConfig:
@@ -546,6 +552,9 @@ def _to_proxy_event(self, event: Dict) -> BaseProxyEvent:
546552
if self._proxy_type == ProxyEventType.APIGatewayProxyEventV2:
547553
logger.debug("Converting event to API Gateway HTTP API contract")
548554
return APIGatewayProxyEventV2(event)
555+
if self._proxy_type == ProxyEventType.LambdaFunctionUrlEvent:
556+
logger.debug("Converting event to Lambda Function URL contract")
557+
return LambdaFunctionUrlEvent(event)
549558
logger.debug("Converting event to ALB contract")
550559
return ALBEvent(event)
551560

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from typing import Callable, Dict, List, Optional
2+
3+
from aws_lambda_powertools.event_handler import CORSConfig
4+
from aws_lambda_powertools.event_handler.api_gateway import ApiGatewayResolver, ProxyEventType
5+
from aws_lambda_powertools.utilities.data_classes import LambdaFunctionUrlEvent
6+
7+
8+
class LambdaFunctionUrlResolver(ApiGatewayResolver):
9+
current_event: LambdaFunctionUrlEvent
10+
11+
def __init__(
12+
self,
13+
cors: Optional[CORSConfig] = None,
14+
debug: Optional[bool] = None,
15+
serializer: Optional[Callable[[Dict], str]] = None,
16+
strip_prefixes: Optional[List[str]] = None,
17+
):
18+
super().__init__(ProxyEventType.LambdaFunctionUrlEvent, cors, debug, serializer, strip_prefixes)

aws_lambda_powertools/logging/correlation_paths.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@
66
APPSYNC_RESOLVER = 'request.headers."x-amzn-trace-id"'
77
APPLICATION_LOAD_BALANCER = 'headers."x-amzn-trace-id"'
88
EVENT_BRIDGE = "id"
9+
LAMBDA_FUNCTION_URL = "requestContext.requestId"
910
S3_OBJECT_LAMBDA = "xAmzRequestId"
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
from aws_lambda_powertools.utilities.data_classes.api_gateway_proxy_event import APIGatewayProxyEventV2
2+
3+
4+
class LambdaFunctionUrlEvent(APIGatewayProxyEventV2):
5+
"""AWS Lambda Function URL event
6+
7+
Notes:
8+
-----
9+
For now, this seems to follow the exact payload as HTTP APIs Payload Format Version 2.0.
10+
Certain keys in this payload format don't make sense for function urls (e.g: `routeKey`).
11+
These keys will always be null.
12+
13+
Documentation:
14+
- https://docs.aws.amazon.com/lambda/latest/dg/urls-invocation.html#urls-payloads
15+
- https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html
16+
17+
"""
18+
19+
pass
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
from aws_lambda_powertools.event_handler import LambdaFunctionUrlResolver, Response, content_types
2+
from aws_lambda_powertools.utilities.data_classes import LambdaFunctionUrlEvent
3+
from tests.functional.utils import load_event
4+
5+
6+
def test_lambda_function_url_event():
7+
# GIVEN a Lambda Function Url type event
8+
app = LambdaFunctionUrlResolver()
9+
10+
@app.post("/my/path")
11+
def foo():
12+
assert isinstance(app.current_event, LambdaFunctionUrlEvent)
13+
assert app.lambda_context == {}
14+
assert app.current_event.request_context.stage is not None
15+
return Response(200, content_types.TEXT_HTML, "foo")
16+
17+
# WHEN calling the event handler
18+
result = app(load_event("lambdaFunctionUrlEvent.json"), {})
19+
20+
# THEN process event correctly
21+
# AND set the current_event type as LambdaFunctionUrlEvent
22+
assert result["statusCode"] == 200
23+
assert result["headers"]["Content-Type"] == content_types.TEXT_HTML
24+
assert result["body"] == "foo"
25+
26+
27+
def test_lambda_function_url_no_matches():
28+
# GIVEN a Lambda Function Url type event
29+
app = LambdaFunctionUrlResolver()
30+
31+
@app.post("/no_match")
32+
def foo():
33+
raise RuntimeError()
34+
35+
# WHEN calling the event handler
36+
result = app(load_event("lambdaFunctionUrlEvent.json"), {})
37+
38+
# THEN process event correctly
39+
# AND return 404 because the event doesn't match any known route
40+
assert result["statusCode"] == 404

0 commit comments

Comments
 (0)