Python Lambda 函数将 DynamoDB 解析为 JSON

Python Lambda Function Parsing DynamoDB's to JSON

我在 Python 开发了一个 AWS Lambda。我在 dynamoDB 中读取数据,但在我想要 return json 数据到 APIGateway 之后。

print(dynamodbTableQueryData)
#{'year': Decimal('2015'), 'info': {'rating': Decimal('0'), 'plot': 'Nothing happens at all.'}, 'title': 'The Big New Movie'}

 return {
    'statusCode': 200,
    'body': json.dumps(dynamodbTableQueryData)
}

如果我写这个,title 在 APIGateway 上 returned:

    return {
        ​'statusCode': 200,
        ​'body': json.dumps(dynamodbTableQueryData['title'])
   ​ }

如果我写这个,year 没有在 APIGateway 上 returned,我有一个错误:

    return {
        ​'statusCode': 200,
        ​'body': json.dumps(dynamodbTableQueryData['year'])
   ​ }

这个错误:

[ERROR] TypeError: Object of type Decimal is not JSON serializable Traceback (most recent call last)

我尝试了这个但没有用:

import boto3
from boto3.dynamodb.types import TypeSerializer, TypeDeserializer
ts= TypeSerializer()
td = TypeDeserializer()

deserialized_data= td.deserialize(dynamodbTableQueryData)
print(deserialized_data)

因为JSON对象只能包含list、dict、str、int、float等特定类型,所以对于Decimal等不支持的类型,datetime,等等,我们应该通过定义自定义序列化器来明确定义它们应该如何被解析。例如,Decimal('2015') 应该是一个字符串 "Decimal(2015)" 或者只是数字部分 "2015" 或者它应该是一个 int 2015 或 float 2015.0 或其他东西。

这里有一个解决方案,如果 Decimal 对象位于内部嵌套中,它也可以递归工作。我们将获得数字的字符串值,例如"2015"(我选择 str 类型是因为返回的 float 可能不一致,具体取决于技术堆栈,例如 1.2 可能被解释为 1.20000001)。这将通过 defaultcls 参数 json.dumps() 实现,如文档所述:

If specified, default should be a function that gets called for objects that can’t otherwise be serialized. It should return a JSON encodable version of the object or raise a TypeError. If not specified, TypeError is raised.

from decimal import Decimal
import json

dynamodbTableQueryData = {'year': Decimal('2015'), 'info': {'rating': Decimal('0'), 'plot': 'Nothing happens at all.'}, 'title': 'The Big New Movie'}

# Solution 1
def to_serializable(val):
    if isinstance(val, Decimal):
        return str(val)
    return val

print("Solution 1")
result = json.dumps(dynamodbTableQueryData['info'], default=to_serializable)
print(result)
result = json.dumps(dynamodbTableQueryData['title'], default=to_serializable)
print(result)
result = json.dumps(dynamodbTableQueryData['year'], default=to_serializable)
print(result)

# Solution 2

class MyJSONEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, Decimal):
            return str(obj)
        else:
            return super().default(obj)

print("Solution 2")
result = json.dumps(dynamodbTableQueryData['info'], cls=MyJSONEncoder)
print(result)
result = json.dumps(dynamodbTableQueryData['title'], cls=MyJSONEncoder)
print(result)
result = json.dumps(dynamodbTableQueryData['year'], cls=MyJSONEncoder)
print(result)

输出

Solution 1
{"rating": "0", "plot": "Nothing happens at all."}
"The Big New Movie"
"2015"
Solution 2
{"rating": "0", "plot": "Nothing happens at all."}
"The Big New Movie"
"2015"