Skip to content

Commit 7be425e

Browse files
docs(jmespath_util): snippets split, improved, and lint (#1419)
Co-authored-by: heitorlessa <[email protected]>
1 parent a71a0e5 commit 7be425e

18 files changed

+575
-163
lines changed

docs/utilities/jmespath_functions.md

Lines changed: 91 additions & 163 deletions
Large diffs are not rendered by default.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"Records": [
3+
{
4+
"messageId": "19dd0b57-b21e-4ac1-bd88-01bbb068cb78",
5+
"receiptHandle": "MessageReceiptHandle",
6+
"body": "{\"customerId\":\"dd4649e6-2484-4993-acb8-0f9123103394\",\"booking\":{\"id\":\"5b2c4803-330b-42b7-811a-c68689425de1\",\"reference\":\"ySz7oA\",\"outboundFlightId\":\"20c0d2f2-56a3-4068-bf20-ff7703db552d\"},\"payment\":{\"receipt\":\"https:\/\/pay.stripe.com\/receipts\/acct_1Dvn7pF4aIiftV70\/ch_3JTC14F4aIiftV700iFq2CHB\/rcpt_K7QsrFln9FgFnzUuBIiNdkkRYGxUL0X\",\"amount\":100}}",
7+
"attributes": {
8+
"ApproximateReceiveCount": "1",
9+
"SentTimestamp": "1523232000000",
10+
"SenderId": "123456789012",
11+
"ApproximateFirstReceiveTimestamp": "1523232000001"
12+
},
13+
"messageAttributes": {},
14+
"md5OfBody": "7b270e59b47ff90a553787216d55d91d",
15+
"eventSource": "aws:sqs",
16+
"eventSourceARN": "arn:aws:sqs:us-east-1:123456789012:MyQueue",
17+
"awsRegion": "us-east-1"
18+
}
19+
]
20+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from aws_lambda_powertools.utilities.jmespath_utils import envelopes, extract_data_from_envelope
2+
from aws_lambda_powertools.utilities.typing import LambdaContext
3+
4+
5+
def handler(event: dict, context: LambdaContext) -> dict:
6+
payload = extract_data_from_envelope(data=event, envelope=envelopes.SQS)
7+
customer_id = payload.get("customerId") # now deserialized
8+
9+
return {"customer_id": customer_id, "message": "success", "statusCode": 200}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"body": "{\"customerId\":\"dd4649e6-2484-4993-acb8-0f9123103394\"}",
3+
"deeply_nested": [
4+
{
5+
"some_data": [
6+
1,
7+
2,
8+
3
9+
]
10+
}
11+
]
12+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from aws_lambda_powertools.utilities.jmespath_utils import extract_data_from_envelope
2+
from aws_lambda_powertools.utilities.typing import LambdaContext
3+
4+
5+
def handler(event: dict, context: LambdaContext) -> dict:
6+
payload = extract_data_from_envelope(data=event, envelope="powertools_json(body)")
7+
customer_id = payload.get("customerId") # now deserialized
8+
9+
# also works for fetching and flattening deeply nested data
10+
some_data = extract_data_from_envelope(data=event, envelope="deeply_nested[*].some_data[]")
11+
12+
return {"customer_id": customer_id, "message": "success", "context": some_data, "statusCode": 200}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import base64
2+
import binascii
3+
import gzip
4+
import json
5+
6+
import powertools_base64_gzip_jmespath_schema as schemas
7+
from jmespath.exceptions import JMESPathTypeError
8+
9+
from aws_lambda_powertools.utilities.typing import LambdaContext
10+
from aws_lambda_powertools.utilities.validation import SchemaValidationError, validate
11+
12+
13+
def lambda_handler(event, context: LambdaContext) -> dict:
14+
try:
15+
validate(event=event, schema=schemas.INPUT, envelope="powertools_base64_gzip(payload) | powertools_json(@)")
16+
17+
# Alternatively, extract_data_from_envelope works here too
18+
encoded_payload = base64.b64decode(event["payload"])
19+
uncompressed_payload = gzip.decompress(encoded_payload).decode()
20+
log: dict = json.loads(uncompressed_payload)
21+
22+
return {
23+
"message": "Logs processed",
24+
"log_group": log.get("logGroup"),
25+
"owner": log.get("owner"),
26+
"success": True,
27+
}
28+
29+
except JMESPathTypeError:
30+
return return_error_message("The powertools_base64_gzip() envelope function must match a valid path.")
31+
except binascii.Error:
32+
return return_error_message("Payload must be a valid base64 encoded string")
33+
except json.JSONDecodeError:
34+
return return_error_message("Payload must be valid JSON (base64 encoded).")
35+
except SchemaValidationError as exception:
36+
# SchemaValidationError indicates where a data mismatch is
37+
return return_error_message(str(exception))
38+
39+
40+
def return_error_message(message: str) -> dict:
41+
return {"message": message, "success": False}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"payload": "H4sIACZAXl8C/52PzUrEMBhFX2UILpX8tPbHXWHqIOiq3Q1F0ubrWEiakqTWofTdTYYB0YWL2d5zvnuTFellBIOedoiyKH5M0iwnlKH7HZL6dDB6ngLDfLFYctUKjie9gHFaS/sAX1xNEq525QxwFXRGGMEkx4Th491rUZdV3YiIZ6Ljfd+lfSyAtZloacQgAkqSJCGhxM6t7cwwuUGPz4N0YKyvO6I9WDeMPMSo8Z4Ca/kJ6vMEYW5f1MX7W1lVxaG8vqX8hNFdjlc0iCBBSF4ERT/3Pl7RbMGMXF2KZMh/C+gDpNS7RRsp0OaRGzx0/t8e0jgmcczyLCWEePhni/23JWalzjdu0a3ZvgEaNLXeugEAAA=="
3+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
INPUT = {
2+
"$schema": "http://json-schema.org/draft-07/schema",
3+
"$id": "http://example.com/example.json",
4+
"type": "object",
5+
"title": "Sample schema",
6+
"description": "The root schema comprises the entire JSON document.",
7+
"examples": [
8+
{
9+
"owner": "123456789012",
10+
"logGroup": "/aws/lambda/powertools-example",
11+
"logStream": "2022/08/07/[$LATEST]d3a8dcaffc7f4de2b8db132e3e106660",
12+
"logEvents": {},
13+
}
14+
],
15+
"required": ["owner", "logGroup", "logStream", "logEvents"],
16+
"properties": {
17+
"owner": {
18+
"$id": "#/properties/owner",
19+
"type": "string",
20+
"title": "The owner",
21+
"examples": ["123456789012"],
22+
"maxLength": 12,
23+
},
24+
"logGroup": {
25+
"$id": "#/properties/logGroup",
26+
"type": "string",
27+
"title": "The logGroup",
28+
"examples": ["/aws/lambda/powertools-example"],
29+
"maxLength": 100,
30+
},
31+
"logStream": {
32+
"$id": "#/properties/logStream",
33+
"type": "string",
34+
"title": "The logGroup",
35+
"examples": ["2022/08/07/[$LATEST]d3a8dcaffc7f4de2b8db132e3e106660"],
36+
"maxLength": 100,
37+
},
38+
"logEvents": {
39+
"$id": "#/properties/logEvents",
40+
"type": "array",
41+
"title": "The logEvents",
42+
"examples": [
43+
"{'id': 'eventId1', 'message': {'username': 'lessa', 'message': 'hello world'}, 'timestamp': 1440442987000}" # noqa E501
44+
],
45+
},
46+
},
47+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import base64
2+
import binascii
3+
import json
4+
from dataclasses import asdict, dataclass, field, is_dataclass
5+
from uuid import uuid4
6+
7+
import powertools_base64_jmespath_schema as schemas
8+
from jmespath.exceptions import JMESPathTypeError
9+
10+
from aws_lambda_powertools.utilities.typing import LambdaContext
11+
from aws_lambda_powertools.utilities.validation import SchemaValidationError, validate
12+
13+
14+
@dataclass
15+
class Order:
16+
user_id: int
17+
product_id: int
18+
quantity: int
19+
price: float
20+
currency: str
21+
order_id: str = field(default_factory=lambda: f"{uuid4()}")
22+
23+
24+
class DataclassCustomEncoder(json.JSONEncoder):
25+
"""A custom JSON encoder to serialize dataclass obj"""
26+
27+
def default(self, obj):
28+
# Only called for values that aren't JSON serializable
29+
# where `obj` will be an instance of Todo in this example
30+
return asdict(obj) if is_dataclass(obj) else super().default(obj)
31+
32+
33+
def lambda_handler(event, context: LambdaContext) -> dict:
34+
35+
# Try to validate the schema
36+
try:
37+
validate(event=event, schema=schemas.INPUT, envelope="powertools_json(powertools_base64(payload))")
38+
39+
# alternatively, extract_data_from_envelope works here too
40+
payload_decoded = base64.b64decode(event["payload"]).decode()
41+
42+
order_payload: dict = json.loads(payload_decoded)
43+
44+
return {
45+
"order": json.dumps(Order(**order_payload), cls=DataclassCustomEncoder),
46+
"message": "order created",
47+
"success": True,
48+
}
49+
except JMESPathTypeError:
50+
return return_error_message(
51+
"The powertools_json(powertools_base64()) envelope function must match a valid path."
52+
)
53+
except binascii.Error:
54+
return return_error_message("Payload must be a valid base64 encoded string")
55+
except json.JSONDecodeError:
56+
return return_error_message("Payload must be valid JSON (base64 encoded).")
57+
except SchemaValidationError as exception:
58+
# SchemaValidationError indicates where a data mismatch is
59+
return return_error_message(str(exception))
60+
61+
62+
def return_error_message(message: str) -> dict:
63+
return {"order": None, "message": message, "success": False}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"payload":"eyJ1c2VyX2lkIjogMTIzLCAicHJvZHVjdF9pZCI6IDEsICJxdWFudGl0eSI6IDIsICJwcmljZSI6IDEwLjQwLCAiY3VycmVuY3kiOiAiVVNEIn0="
3+
}

0 commit comments

Comments
 (0)