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
)。这将通过 default
和 cls
参数 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"
我在 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
)。这将通过 default
和 cls
参数 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"