Skip to content

Commit ad6a85b

Browse files
stephenbawksleandrodamascenaheitorlessa
authored
feat(event_sources): add support for VPC Lattice events (#2358)
Co-authored-by: Leandro Damascena <[email protected]> Co-authored-by: Heitor Lessa <[email protected]>
1 parent f0dcb8f commit ad6a85b

File tree

7 files changed

+177
-0
lines changed

7 files changed

+177
-0
lines changed

aws_lambda_powertools/utilities/data_classes/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from .ses_event import SESEvent
2121
from .sns_event import SNSEvent
2222
from .sqs_event import SQSEvent
23+
from .vpc_lattice import VPCLatticeEvent
2324

2425
__all__ = [
2526
"APIGatewayProxyEvent",
@@ -42,4 +43,5 @@
4243
"SNSEvent",
4344
"SQSEvent",
4445
"event_source",
46+
"VPCLatticeEvent",
4547
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import base64
2+
from typing import Any, Dict, Optional
3+
4+
from aws_lambda_powertools.utilities.data_classes.common import (
5+
DictWrapper,
6+
get_header_value,
7+
)
8+
9+
10+
class VPCLatticeEvent(DictWrapper):
11+
@property
12+
def body(self) -> str:
13+
"""The VPC Lattice body."""
14+
return self["body"]
15+
16+
@property
17+
def json_body(self) -> Any:
18+
"""Parses the submitted body as json"""
19+
if self._json_data is None:
20+
self._json_data = self._json_deserializer(self.decoded_body)
21+
return self._json_data
22+
23+
@property
24+
def headers(self) -> Dict[str, str]:
25+
"""The VPC Lattice event headers."""
26+
return self["headers"]
27+
28+
@property
29+
def is_base64_encoded(self) -> bool:
30+
"""A boolean flag to indicate if the applicable request payload is Base64-encode"""
31+
return self["is_base64_encoded"]
32+
33+
@property
34+
def decoded_body(self) -> str:
35+
"""Dynamically base64 decode body as a str"""
36+
body: str = self["body"]
37+
if self.is_base64_encoded:
38+
return base64.b64decode(body.encode()).decode()
39+
return body
40+
41+
@property
42+
def method(self) -> str:
43+
"""The VPC Lattice method used. Valid values include: DELETE, GET, HEAD, OPTIONS, PATCH, POST, and PUT."""
44+
return self["method"]
45+
46+
@property
47+
def query_string_parameters(self) -> Dict[str, str]:
48+
"""The request query string parameters."""
49+
return self["query_string_parameters"]
50+
51+
@property
52+
def raw_path(self) -> str:
53+
"""The raw VPC Lattice request path."""
54+
return self["raw_path"]
55+
56+
def get_query_string_value(self, name: str, default_value: Optional[str] = None) -> Optional[str]:
57+
"""Get query string value by name
58+
59+
Parameters
60+
----------
61+
name: str
62+
Query string parameter name
63+
default_value: str, optional
64+
Default value if no value was found by name
65+
Returns
66+
-------
67+
str, optional
68+
Query string parameter value
69+
"""
70+
params = self.query_string_parameters
71+
return default_value if params is None else params.get(name, default_value)
72+
73+
def get_header_value(
74+
self, name: str, default_value: Optional[str] = None, case_sensitive: Optional[bool] = False
75+
) -> Optional[str]:
76+
"""Get header value by name
77+
78+
Parameters
79+
----------
80+
name: str
81+
Header name
82+
default_value: str, optional
83+
Default value if no value was found by name
84+
case_sensitive: bool
85+
Whether to use a case-sensitive look up
86+
Returns
87+
-------
88+
str, optional
89+
Header value
90+
"""
91+
return get_header_value(self.headers, name, default_value, case_sensitive)

docs/utilities/data_classes.md

+19
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ Log Data Event for Troubleshooting
102102
| [SES](#ses) | `SESEvent` |
103103
| [SNS](#sns) | `SNSEvent` |
104104
| [SQS](#sqs) | `SQSEvent` |
105+
| [VPC Lattice](#vpc-lattice) | `VPCLatticeEvent` |
105106

106107
???+ info
107108
The examples provided below are far from exhaustive - the data classes themselves are designed to provide a form of
@@ -1121,6 +1122,24 @@ This example is based on the AWS Blog post [Introducing Amazon S3 Object Lambda
11211122
do_something_with(record.body)
11221123
```
11231124

1125+
### VPC Lattice
1126+
1127+
You can register your Lambda functions as targets within an Amazon VPC Lattice service network. By doing this, your Lambda function becomes a service within the network, and clients that have access to the VPC Lattice service network can call your service.
1128+
1129+
[Click here](https://docs.aws.amazon.com/lambda/latest/dg/services-vpc-lattice.html){target="_blank"} for more information about using AWS Lambda with Amazon VPC Lattice.
1130+
1131+
=== "app.py"
1132+
1133+
```python hl_lines="2 8"
1134+
--8<-- "examples/event_sources/src/vpc_lattice.py"
1135+
```
1136+
1137+
=== "Lattice Example Event"
1138+
1139+
```json
1140+
--8<-- "examples/event_sources/src/vpc_lattice_payload.json"
1141+
```
1142+
11241143
## Advanced
11251144

11261145
### Debugging
+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
from aws_lambda_powertools import Logger
2+
from aws_lambda_powertools.utilities.data_classes import VPCLatticeEvent, event_source
3+
from aws_lambda_powertools.utilities.typing import LambdaContext
4+
5+
logger = Logger()
6+
7+
8+
@event_source(data_class=VPCLatticeEvent)
9+
def lambda_handler(event: VPCLatticeEvent, context: LambdaContext):
10+
logger.info(event.body)
11+
12+
response = {
13+
"isBase64Encoded": False,
14+
"statusCode": 200,
15+
"headers": {"Content-Type": "application/text"},
16+
"body": "Event Response to VPC Lattice 🔥🚀🔥",
17+
}
18+
19+
return response
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"raw_path": "/testpath",
3+
"method": "GET",
4+
"headers": {
5+
"user_agent": "curl/7.64.1",
6+
"x-forwarded-for": "10.213.229.10",
7+
"host": "test-lambda-service-3908sdf9u3u.dkfjd93.vpc-lattice-svcs.us-east-2.on.aws",
8+
"accept": "*/*"
9+
},
10+
"query_string_parameters": {
11+
"order-id": "1"
12+
},
13+
"body": "eyJ0ZXN0IjogImV2ZW50In0=",
14+
"is_base64_encoded": true
15+
}

tests/events/vpcLatticeEvent.json

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"raw_path": "/testpath",
3+
"method": "GET",
4+
"headers": {
5+
"user_agent": "curl/7.64.1",
6+
"x-forwarded-for": "10.213.229.10",
7+
"host": "test-lambda-service-3908sdf9u3u.dkfjd93.vpc-lattice-svcs.us-east-2.on.aws",
8+
"accept": "*/*"
9+
},
10+
"query_string_parameters": {
11+
"order-id": "1"
12+
},
13+
"body": "eyJ0ZXN0IjogImV2ZW50In0=",
14+
"is_base64_encoded": true
15+
}

tests/functional/test_data_classes.py

+16
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
SESEvent,
2626
SNSEvent,
2727
SQSEvent,
28+
VPCLatticeEvent,
2829
)
2930
from aws_lambda_powertools.utilities.data_classes.api_gateway_authorizer_event import (
3031
APIGatewayAuthorizerEventV2,
@@ -2041,3 +2042,18 @@ def test_api_gateway_route_arn_parser():
20412042
details = parse_api_gateway_arn(arn)
20422043
assert details.resource == ""
20432044
assert details.arn == arn + "/"
2045+
2046+
2047+
def test_vpc_lattice_event():
2048+
event = VPCLatticeEvent(load_event("vpcLatticeEvent.json"))
2049+
2050+
assert event.raw_path == event["raw_path"]
2051+
assert event.get_query_string_value("order-id") == "1"
2052+
assert event.get_header_value("user_agent") == "curl/7.64.1"
2053+
assert event.decoded_body == '{"test": "event"}'
2054+
assert event.json_body == {"test": "event"}
2055+
assert event.method == event["method"]
2056+
assert event.headers == event["headers"]
2057+
assert event.query_string_parameters == event["query_string_parameters"]
2058+
assert event.body == event["body"]
2059+
assert event.is_base64_encoded == event["is_base64_encoded"]

0 commit comments

Comments
 (0)