I am trying to write a serverless back-end for an application with AWS Lambda, and am running into the error in the title. The error occurs when testing with API Gateway proxy integration, but the function works fine when tested in the Lambda console.
Here is the error:
{
"errorMessage":"string indices must be integers",
"errorType":"TypeError",
"stackTrace":[
[
"/var/task/auth_login.py",
17,
"lambda_handler",
"response = get_user(payload)"
],
[
"/var/task/shifty_utils/__init__.py",
22,
"get_user",
"table = dynamo.Table(user['company'] + '_users')"
]
]
}
Here is context for where it occurs:
def lambda_handler(event, context):
payload = event['body']
response = get_user(payload)
def get_user(user):
try:
table = dynamo.Table(user['company'] + '_users')
response = table.get_item(
Key={
'userId': user['userId'],
'position': user['position']
}
)
except ClientError as e:
print(e.response['Error']['Message'])
return {'message': e.response['Error']['Message']}
else:
return response
Basically proxy integration seems to be reading in the event object as a JSON formatted string, as opposed to a dict, but here's what happens if I adjust my code for that:
{
"errorMessage":"the JSON object must be str, bytes or bytearray, not 'dict'",
"errorType":"TypeError",
"stackTrace":[
[
"/var/task/auth_login.py",
15,
"lambda_handler",
"payload = json.loads(event)"
],
[
"/var/lang/lib/python3.6/json/__init__.py",
348,
"loads",
"'not {!r}'.format(s.__class__.__name__))"
]
]
}
I can't win. Any help is appreciated.
You've identified the issue. However you're trying to convert a dict
to dict
.
This is what you have:
json.loads(event) # event is a dict
The body part as you have rightly identified is what is getting in as str
.
This is what you should have:
json.loads(event['body'])
One more step is to make it client-agnostic.
if isinstance(event['body'], (unicode, str)):
body = json.loads(event['body'])
This is because event['body']
is not a dict
but a str
. (I ran into this problem when decoding an SQS triggered event)
In case if anyone ran into a problem when a value of json.loads(event['body'])
is again not dict
but str
, here is a solution that decodes str to dict recursively.
import json
def to_dict(obj : object) -> dict:
""" Serialize Object to Dictionary Recursively
Arguments:
obj {object} -- string, list, or dictionary to be serialize
Returns:
dict -- Serialized Dictionary
"""
if isinstance(obj, dict):
data = {}
for k, v in obj.items():
data[k] = to_dict(v)
return data
elif hasattr(obj, "_ast"):
return to_dict(obj._ast())
elif hasattr(obj, "__iter__") and not isinstance(obj, str):
return [to_dict(v) for v in obj]
elif hasattr(obj, "__dict__"):
data = {key : to_dict(value) for key, value in obj.__dict__.items() if
not callable(value) and not key.startswith('_')}
elif isinstance(obj, str):
try:
data = {}
obj = json.loads(obj)
for k, v in obj.items():
data[k] = to_dict(v)
return data
except:
return obj
else:
return obj
Example Usage:
test = {'Records': ['{"s3": "{\\"bucket\\": \\"bucketname\\"}"}', '{"s3": "{\\"bucket\\": \\"bucketname\\"}"}']}
print(to_dict(test)['Records'][0]['s3']['bucket'])
This should print "bucketname".
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With