Skip to content

Commit 0d46d39

Browse files
committed
docs(jmespath): expose jmespath powertools functions & extract fn
1 parent e05901e commit 0d46d39

File tree

2 files changed

+116
-17
lines changed

2 files changed

+116
-17
lines changed

docs/utilities/idempotency.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ Imagine the function executes successfully, but the client never receives the re
209209
!!! warning "Idempotency for JSON payloads"
210210
The payload extracted by the `event_key_jmespath` is treated as a string by default, so will be sensitive to differences in whitespace even when the JSON payload itself is identical.
211211

212-
To alter this behaviour, we can use the [JMESPath built-in function](/utilities/jmespath_functions) *powertools_json()* to treat the payload as a JSON object rather than a string.
212+
To alter this behaviour, we can use the [JMESPath built-in function](jmespath_functions.md#powertools_json-function) `powertools_json()` to treat the payload as a JSON object rather than a string.
213213

214214
=== "payment.py"
215215

docs/utilities/jmespath_functions.md

+115-16
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,106 @@ title: JMESPath Functions
33
description: Utility
44
---
55

6-
You might have events or responses that contain non-encoded JSON, where you need to decode so that you can access portions of the object or ensure the Powertools utility receives a JSON object. This is a common use case when using the [validation](/utilities/validation) or [idempotency](/utilities/idempotency) utilities.
6+
!!! tip "JMESPath is a query language for JSON used by AWS CLI, AWS Python SDK, and AWS Lambda Powertools for Python."
77

8-
## Built-in JMESPath functions
8+
Built-in [JMESPath](https://jmespath.org/){target="_blank"} Functions to easily deserialize common encoded JSON payloads in Lambda functions.
9+
10+
## Key features
11+
12+
* Deserialize JSON from JSON strings, base64, and compressed data
13+
* Use JMESPath to extract and combine data recursively
14+
15+
## Getting started
16+
17+
You might have events that contains encoded JSON payloads as string, base64, or even in compressed format. It is a common use case to decode and extract them partially or fully as part of your Lambda function invocation.
18+
19+
Lambda Powertools also have utilities like [validation](validation.md), [idempotency](idempotency.md), or [feature flags](feature_flags.md) where you might need to extract a portion of your data before using them.
20+
21+
### Extracting data
22+
23+
You can use the `extract_data_from_envelope` function along with any [JMESPath expression](https://jmespath.org/tutorial.html){target="_blank"}.
24+
25+
=== "app.py"
26+
27+
```python hl_lines="1 7"
28+
from aws_lambda_powertools.utilities.jmespath_utils import extract_data_from_envelope
29+
30+
from aws_lambda_powertools.utilities.typing import LambdaContext
31+
32+
33+
def handler(event: dict, context: LambdaContext):
34+
payload = extract_data_from_envelope(data=event, envelope="powertools_json(body)")
35+
customer = payload.get("customerId") # now deserialized
36+
...
37+
```
38+
39+
=== "event.json"
40+
41+
```json
42+
{
43+
"body": "{\"customerId\":\"dd4649e6-2484-4993-acb8-0f9123103394\"}"
44+
}
45+
```
46+
47+
### Built-in envelopes
48+
49+
We provide built-in envelopes for popular JMESPath expressions used when looking to decode/deserialize JSON objects within AWS Lambda Event Sources.
50+
51+
=== "app.py"
52+
53+
```python hl_lines="1 7"
54+
from aws_lambda_powertools.utilities.jmespath_utils import extract_data_from_envelope, envelopes
55+
56+
from aws_lambda_powertools.utilities.typing import LambdaContext
57+
58+
59+
def handler(event: dict, context: LambdaContext):
60+
payload = extract_data_from_envelope(data=event, envelope=envelopes.SNS)
61+
customer = payload.get("customerId") # now deserialized
62+
...
63+
```
64+
65+
=== "event.json"
66+
67+
```json hl_lines="6"
68+
{
69+
"Records": [
70+
{
71+
"messageId": "19dd0b57-b21e-4ac1-bd88-01bbb068cb78",
72+
"receiptHandle": "MessageReceiptHandle",
73+
"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}}",
74+
"attributes": {
75+
"ApproximateReceiveCount": "1",
76+
"SentTimestamp": "1523232000000",
77+
"SenderId": "123456789012",
78+
"ApproximateFirstReceiveTimestamp": "1523232000001"
79+
},
80+
"messageAttributes": {},
81+
"md5OfBody": "7b270e59b47ff90a553787216d55d91d",
82+
"eventSource": "aws:sqs",
83+
"eventSourceARN": "arn:aws:sqs:us-east-1:123456789012:MyQueue",
84+
"awsRegion": "us-east-1"
85+
}
86+
]
87+
}
88+
```
89+
90+
These are all built-in envelopes you can use along with their expression as a reference:
91+
92+
Envelope | JMESPath expression
93+
------------------------------------------------- | ---------------------------------------------------------------------------------
94+
**`API_GATEWAY_REST`** | `powertools_json(body)`
95+
**`API_GATEWAY_HTTP`** | `API_GATEWAY_REST`
96+
**`SQS`** | `Records[*].powertools_json(body)`
97+
**`SNS`** | `Records[0].Sns.Message | powertools_json(@)`
98+
**`EVENTBRIDGE`** | `detail`
99+
**`CLOUDWATCH_EVENTS_SCHEDULED`** | `EVENTBRIDGE`
100+
**`KINESIS_DATA_STREAM`** | `Records[*].kinesis.powertools_json(powertools_base64(data))`
101+
**`CLOUDWATCH_LOGS`** | `awslogs.powertools_base64_gzip(data) | powertools_json(@).logEvents[*]`
102+
103+
## Advanced
104+
105+
### Built-in JMESPath functions
9106
You can use our built-in JMESPath functions within your expressions to do exactly that to decode JSON Strings, base64, and uncompress gzip data.
10107

11108
!!! info
@@ -134,33 +231,35 @@ This sample will decompress and decode base64 data, then use JMESPath pipeline e
134231
!!! warning
135232
This should only be used for advanced use cases where you have special formats not covered by the built-in functions.
136233

137-
This will **replace all provided built-in functions such as `powertools_json`, so you will no longer be able to use them**.
138-
139234
For special binary formats that you want to decode before applying JSON Schema validation, you can bring your own [JMESPath function](https://github.com/jmespath/jmespath.py#custom-functions){target="_blank"} and any additional option via `jmespath_options` param.
140235

141-
=== "custom_jmespath_function.py"
236+
In order to keep the built-in functions from Powertools, you can subclass from `PowertoolsFunctions`:
142237

143-
```python hl_lines="2 6-10 14"
144-
from aws_lambda_powertools.utilities.validation import validator
145-
from jmespath import functions
238+
=== "custom_jmespath_function.py"
146239

147-
import schemas
240+
```python hl_lines="2-3 6-9 11 17"
241+
from aws_lambda_powertools.utilities.jmespath_utils import (
242+
PowertoolsFunctions, extract_data_from_envelope)
243+
from jmespath.functions import signature
148244

149-
class CustomFunctions(functions.Functions):
150245

151-
@functions.signature({'types': ['string']})
246+
class CustomFunctions(PowertoolsFunctions):
247+
@signature({'types': ['string']}) # Only decode if value is a string
152248
def _func_special_decoder(self, s):
153249
return my_custom_decoder_logic(s)
154250

155251
custom_jmespath_options = {"custom_functions": CustomFunctions()}
156252

157-
@validator(schema=schemas.INPUT, jmespath_options=**custom_jmespath_options)
158253
def handler(event, context):
159-
return event
254+
# use the custom name after `_func_`
255+
extract_data_from_envelope(data=event,
256+
envelope="special_decoder(body)",
257+
jmespath_options=**custom_jmespath_options)
258+
...
160259
```
161260

162-
=== "schemas.py"
261+
=== "event.json"
163262

164-
```python hl_lines="7 14 16 23 39 45 47 52"
165-
--8<-- "docs/shared/validation_basic_jsonschema.py"
263+
```json
264+
{"body": "custom_encoded_data"}
166265
```

0 commit comments

Comments
 (0)