You have to use json.loads not json.dumps.
Try this:
import json
event = {
"Records":[
{
"messageId":"916f5e95-b2f6-4148-9c62-2ac8e764f06c",
"receiptHandle":"AQEBmLuoGWtLtFFgvyCFdSPMJh2HKgHOIPWNUq22EOwCzGT8iILZm97CE6j4J6oR71ZpDr3sgxQcJyVZ+dmmvGl+fFftT9GCJqZYrjMGsR2Q6WsMd8ciI8bTtDXyvsk8ektd7UGfh4gxIZoFp7WUKVRcMEeBkubKd8T4/Io81D0l/AK7MxcEfCj40vWEsex1kkGmMRlBtdSeGyy7fJgUq5CFAYWciiWtbSit8S0Y38xZPmsIFhoxP0egQRoJcW4aUgMi469Gj5+khizetybtgC8vux5NCg/IejxcCueXkQ7LKVF8kfRdqRSUYB6DsOrGgfmZpK4wpXIarByNz0R2p7J88meYpj2IVULv/emXsSYaKG4rXnpbH4J9ijbLWckYLAd7wPDzCYri1ZSTgAz0kchsEw==",
"body":"{\n\"name\": \"aniket\",\n\"tag\": \"hello\"\n}",
"attributes":{
"ApproximateReceiveCount":"1",
"SentTimestamp":"1602046897707",
"SenderId":"AIDAR3BXDV4FCWXL56NUU",
"ApproximateFirstReceiveTimestamp":"1602046897712"
},
"messageAttributes":{
},
"md5OfBody":"98da683a47692b39c1d43bd4fa21ed89",
"eventSource":"aws:sqs",
"eventSourceARN":"arn:aws:sqs:ap-south-1:126817120010:documentation",
"awsRegion":"ap-south-1"
}
]
}
parsed = json.loads(event['Records'][0]['body'])
print(json.dumps(parsed, indent=4, sort_keys=True))
Output:
{
"name": "aniket",
"tag": "hello"
}
Answer from baduker on Stack OverflowHow to retrieve well formatted JSON from AWS Lambda using Python - Stack Overflow
AWS Python Lambda Integration to Return JSON response directly - Serverless Framework - Serverless Forums
Access json request from python in python AWS lambda function - Stack Overflow
Malformed JSON in AWS Lambda using Python.
You have to use json.loads not json.dumps.
Try this:
import json
event = {
"Records":[
{
"messageId":"916f5e95-b2f6-4148-9c62-2ac8e764f06c",
"receiptHandle":"AQEBmLuoGWtLtFFgvyCFdSPMJh2HKgHOIPWNUq22EOwCzGT8iILZm97CE6j4J6oR71ZpDr3sgxQcJyVZ+dmmvGl+fFftT9GCJqZYrjMGsR2Q6WsMd8ciI8bTtDXyvsk8ektd7UGfh4gxIZoFp7WUKVRcMEeBkubKd8T4/Io81D0l/AK7MxcEfCj40vWEsex1kkGmMRlBtdSeGyy7fJgUq5CFAYWciiWtbSit8S0Y38xZPmsIFhoxP0egQRoJcW4aUgMi469Gj5+khizetybtgC8vux5NCg/IejxcCueXkQ7LKVF8kfRdqRSUYB6DsOrGgfmZpK4wpXIarByNz0R2p7J88meYpj2IVULv/emXsSYaKG4rXnpbH4J9ijbLWckYLAd7wPDzCYri1ZSTgAz0kchsEw==",
"body":"{\n\"name\": \"aniket\",\n\"tag\": \"hello\"\n}",
"attributes":{
"ApproximateReceiveCount":"1",
"SentTimestamp":"1602046897707",
"SenderId":"AIDAR3BXDV4FCWXL56NUU",
"ApproximateFirstReceiveTimestamp":"1602046897712"
},
"messageAttributes":{
},
"md5OfBody":"98da683a47692b39c1d43bd4fa21ed89",
"eventSource":"aws:sqs",
"eventSourceARN":"arn:aws:sqs:ap-south-1:126817120010:documentation",
"awsRegion":"ap-south-1"
}
]
}
parsed = json.loads(event['Records'][0]['body'])
print(json.dumps(parsed, indent=4, sort_keys=True))
Output:
{
"name": "aniket",
"tag": "hello"
}
Try using json.loads(string) to deserialize the json.
Also, I don't believe you need to specify the index [0] since 'body' is an object and not an array.
In your lambda function you should return a response object with a JSON object in the response body.
# Lambda Function
def get_json(event, context):
"""Retrieve JSON from server."""
# Business Logic Goes Here.
response = {
"statusCode": 200,
"headers": {},
"body": json.dumps({
"message": "This is the message in a JSON object."
})
}
return response
Don't use json.dumps()
I had a similar issue, and when I just returned "body": content instead of "body": json.dumps(content) I could easily access and manipulate my data. Before that, I got that weird form that looks like JSON, but it's not.
Hello LeanPython Sub-reddit!
I come to you because I have a problem formatting JSON in AWS Lambda.
I would like to tell you a little more, what happens is that I am developing an API in AWS Lambda, I created the database in PostgreSQL, and I am using Python to perform the queries, what happens is that I had a datatimes management error, because these values could not be formatted in a JSON, so I decided to make an encoder in a class which is responsible for carrying out this process of formatting it to JSON, but what happens is that it generates a JSON which is very poorly readable, in addition to being a headache when trying to manipulate it in the Frontend, below I will show you what I did and I would like to consult with you about a possible solution to this problem, please.
Below you will find the encoder class I was talking about:
class DateTimeEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, datetime):
return o.isoformat()
return json.JSONEncoder.default(self, o)In the following function I am using json.dumps to format the output of the database query into JSON, in conjunction with the encoder:
def lambda_handler(event, context):
cur = conn.cursor(cursor_factory=RealDictCursor)
cur.execute("SELECT * FROM users")
results = cur.fetchall()
return json.dumps(results, cls=DateTimeEncoder)When deploying this in AWS in a Lambda, and when making the HTTP request through Postman, it generates the following poorly formatted output:
"[{\"id_usuario\": 2, \"cc\": \"123456789\", \"telefono\": \"987654321\", \"nombre\": \"John\", \"apellido\": \"Doe\", \"fecha_registro\": \"2023-07-03T02:34:38.452359\"}, {\"id_usuario\": 3, \"cc\": \"1013655876\", \"telefono\": \"2085686\", \"nombre\": \"Jane\", \"apellido\": \"Doe\", \"fecha_registro\": \"2023-07-03T20:08:42.603593\"}]"What I want is for the above JSON to look like this:
[
{
"id_usuario": 2,
"cc": "123456789",
"telefono": "987654321",
"nombre": "John",
"apellido": "Doe",
"fecha_registro": "2023-07-03T02:34:38.452359"
},
{
"id_usuario": 3,
"cc": "1013655876",
"telefono": "2085686",
"nombre": "Jane",
"apellido": "Doe",
"fecha_registro": "2023-07-03T20:08:42.603593"
}
]If you ask me, I have made other queries that have not had to use the json.dumps and it has generated the JSON with the correct format, however, when I implement the json.dumps in conjunction with the encoder, it generates that output which is difficult to read, I sincerely hope you can help me because I don't know what else to do.
I'm not sure if this is what you want, but you can just do 'body': json_data. I tested this now in my λ function:
Lambda function
import json
def lambda_handler(event, context):
json_data = [{"Dp_Record_Id": 2,
"DP_TYPE": "NSDL",
"DP_ID": "40877589",
"CLIENT_ID": "1232",
"Default_flag": "Y"}]
return {'statusCode': 200,
'headers': {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": 'GET, POST, PUT, DELETE, OPTIONS'
},
'body': json_data
}
Result
Response:
{
"statusCode": 200,
"headers": {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS"
},
"body": [
{
"Dp_Record_Id": 2,
"DP_TYPE": "NSDL",
"DP_ID": "40877589",
"CLIENT_ID": "1232",
"Default_flag": "Y"
}
]
}
I ran into the same issue while I was creating an API by doing things from my memory. Posting this answer for my future self and others.
The issue was that whatever I return in the lambda is getting passed as response to the API. Instead only the data inside body should be passed as response.
This was happening because when I created the resource I forgot to check the checkbox to Use Lambda Proxy Integration. Here is what you have to do:
- Delete your existing method and create a new one. This time make sure you check Use Lambda Proxy Integration.

- Create a deployment to your stage. Until this is done, the change will not reflect. This is where I got stuck and spend most of my time.
So there are 3 problems:
Problem 1: In your example event, ['Records'][0]['Sns']['Message'] is a str in JSON format. That means that you need to parse to a dict like this:
message = event['Records'][0]['Sns']['Message']
message = json.loads(message)
Problem 2: message['Trigger']['Dimensions'] is a list but you are trying to access it like if it were a dict. So you only need to change your code to:
message = message['Trigger']['Dimensions'][0]['name']
Problem 3: Message is a str that means that you need to verify that is a plain str or json str (otherwise you are going to have problems with multiple structures and types). For that your code could look like:
message = event['Records'][0]['Sns']['Message']
if isinstance(message, str):
try:
message = json.loads(message)
except Exception as e:
print(e) # Or do nothing, this is just to log the error
elif isinstance(message, list):
message = message[0]
# Maybe evaluate bool, tuple, etc other types
print('RESPONSE', message['Trigger']['Dimensions'][0]['name'] if isinstance(message, dict) else message)
However I would also recommend to make it more extensible iterating the elements that you know are list. And for safety reasons (trying to avoid null pointer exceptions), use the get() function with a default value. http://www.tutorialspoint.com/python/dictionary_get.htm . Try maybe to create a function to parse structures and make it reusable.
Good luck!
Just as Records is a list, so you use ['Records'][0]['Sns']..., so is Dimensions, so again you need to access the first element.
When you invoke the lambda locally or through the Lambda console, you are invoking that lambda directly and so your lambda receives exactly what you're sending.
When you invoke it through API Gateway, API Gateway creates the event object for you based on your HTTP request. It adds the HTTP headers, path, query strings, payload, etc.
Here's a summary of what you're getting as an event from an API Gateway invocation:
{
"resource": "Resource path",
"path": "Path parameter",
"httpMethod": "Incoming request's method name"
"headers": {Incoming request headers}
"queryStringParameters": {query string parameters }
"pathParameters": {path parameters}
"stageVariables": {Applicable stage variables}
"requestContext": {Request context, including authorizer-returned key-value pairs}
"body": "A JSON string of the request payload."
"isBase64Encoded": "A boolean flag to indicate if the applicable request payload is Base64-encode"
}
Reference: http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-set-up-simple-proxy.html#api-gateway-simple-proxy-for-lambda-input-format
As you can see, the body will be sent to you as a string which you can parse using json.loads().
- The request is fully packaged and sent as a single string in the
'body'key of theeventdict. - This behaviour is different from the test console or invoking from CLI which has only the payload in the
eventdict meaningevent.get('type')works directly.
Example code showing how to access the value of "type" key in payload:
import json
def lambda_handler(event, context):
body_str = event.get("body", "{}")
body_str = body_str if body_str else "{}"
body_obj = json.loads(body_str)
a = body_obj.get("type", "")