Fabien Punin
07/24/2025, 9:31 PMMarvin
07/24/2025, 9:31 PMMarvin
07/24/2025, 9:32 PMjinja2
{{ body.Message }} {# Access the SNS Message field #}
2. For Parsing Nested JSON String
Since AWS SNS typically sends the actual message in the "Message" field as a JSON string, you'll need to use Prefect's built-in json_loads filter:
jinja2
{% set parsed_message = body.Message | json_loads %}
{{ parsed_message.your_attribute }}
Here are some practical examples:
jinja2
{# Access basic SNS fields #}
Topic ARN: {{ body.TopicArn }}
Message ID: {{ body.MessageId }}
{# Parse and access the JSON message content #}
{% set data = body.Message | json_loads %}
User ID: {{ data.user_id }}
Status: {{ data.status }}
{# Using default values for safety #}
Status: {{ data.status | default('unknown') }}
Some important tips:
1. Always use the default filter when accessing fields that might not exist to prevent template errors:
jinja2
{{ data.optional_field | default('fallback_value') }}
2. For keys that aren't valid Python identifiers, use bracket notation:
jinja2
{{ data['special-key-with-hyphens'] }}
3. You can combine multiple filters:
jinja2
{{ body.Message | json_loads | tojson }}
4. For debugging, you can print the entire parsed structure:
jinja2
Raw Message: {{ body.Message }}
Parsed Data: {{ body.Message | json_loads | tojson }}
Remember that the webhook needs to be configured with the correct Content-Type (application/json) to ensure proper JSON parsing of the incoming SNS message.
Would you like me to provide more specific examples based on your particular JSON structure or use case?Fabien Punin
07/24/2025, 9:34 PMFabien Punin
07/24/2025, 9:34 PMMarvin
07/24/2025, 9:35 PMMarvin
07/24/2025, 9:35 PMbody variable in your template.
2. For nested JSON strings (like in AWS SNS messages), you might need to handle the parsing in your flow rather than in the webhook template itself, as complex JSON manipulation in webhook templates can be tricky.
I recommend one of these approaches:
1. Simple Approach: Pass the raw message to your flow and handle parsing there:
jinja2
{{ body.Message }} {# Pass the raw message string to your flow #}
Then in your flow:
python
import json
@flow
def handle_sns_message(message: str):
data = json.loads(message)
# Now you can work with the parsed JSON
2. Alternative Approach: If you must handle it in the webhook template, you can try using Jinja2's built-in from_json filter (if available in your environment):
jinja2
{% set message_data = body.Message | from_json %}
{{ message_data.your_field }}
I apologize for my earlier incorrect suggestion about json_loads. Would you like me to provide more specific guidance based on your particular use case or JSON structure?Nate
07/24/2025, 11:03 PMFabien Punin
07/25/2025, 7:41 AM{\n \"Type\" : \"Notification\",\n \"MessageId\" : \"XXX\",\n \"TopicArn\" : \"XXX\",\n \"Message\" : \"{\\\"customerId\\\": \\\"XXX\\\", \\\"status\\\": \\\"XXX\\\"}\",\n \"Timestamp\" : \"XXX\",\n \"SignatureVersion\" : \"XXX\" \n}
I'm struggling to extract the Message data properly, because of the nested escaped json string. Currently my template looks like this, but it's feels terrible 🙂
{% set message_part = body.Message %}
{% set message_cleaned = message_part | replace('\\"', '"') %}
{# Extract the customer_id #}
{% set customer_id = message_cleaned.split('"customerId":"')[1].split('"')[0] %}
{
"event": "xxx",
"resource": {
"prefect.resource.id": "xxx"
},
"payload": {
"customer_id": "{{ customer_id }}"
}
}
Is there a better way?