Skip to content

Bug: Mongo ObjectIds not serializing out of the box #3892

Closed
@aitchnyu

Description

@aitchnyu

Expected Behaviour

My app has a custom serializer. I used enable_validation. A dict with Mongo ObjectId should have been serialized.

from bson import json_util
...
def custom_serializer(obj) -> str:
    ...
    """Your custom serializer function ApiGatewayResolver will use"""
    return json_util.dumps(obj)

app = APIGatewayRestResolver(serializer=custom_serializer, enable_validation=True)

Current Behaviour

If we use enable_validation, the openapi modules uses its own encoders which cannot handle ObjectIds.

Traceback (most recent call last):
File "/var/task/aws_lambda_powertools/event_handler/openapi/encoders.py", line 265, in _dump_other
data = dict(obj)
TypeError: 'ObjectId' object is not iterable
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/var/task/aws_lambda_powertools/event_handler/openapi/encoders.py", line 269, in _dump_other
data = vars(obj)
TypeError: vars() argument must have __dict__ attribute
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/var/task/aws_lambda_powertools/event_handler/api_gateway.py", line 1985, in _call_route
route(router_middlewares=self._router_middlewares, app=self, route_arguments=route_arguments),
File "/var/task/aws_lambda_powertools/event_handler/api_gateway.py", line 400, in __call__
return self._middleware_stack(app)
File "/var/task/aws_lambda_powertools/event_handler/api_gateway.py", line 1291, in __call__
return self.current_middleware(app, self.next_middleware)
File "/var/task/aws_lambda_powertools/event_handler/middlewares/base.py", line 121, in __call__
return self.handler(app, next_middleware)
File "/var/task/aws_lambda_powertools/event_handler/middlewares/openapi_validation.py", line 121, in handler
return self._handle_response(route=route, response=response)
File "/var/task/aws_lambda_powertools/event_handler/middlewares/openapi_validation.py", line 128, in _handle_response
response.body = self._serialize_response(
File "/var/task/aws_lambda_powertools/event_handler/middlewares/openapi_validation.py", line 187, in _serialize_response
return jsonable_encoder(response_content)
File "/var/task/aws_lambda_powertools/event_handler/openapi/encoders.py", line 108, in jsonable_encoder
return _dump_dict(
File "/var/task/aws_lambda_powertools/event_handler/openapi/encoders.py", line 212, in _dump_dict
encoded_value = jsonable_encoder(
File "/var/task/aws_lambda_powertools/event_handler/openapi/encoders.py", line 138, in jsonable_encoder
return _dump_other(
File "/var/task/aws_lambda_powertools/event_handler/openapi/encoders.py", line 272, in _dump_other
raise ValueError(errors) from e
ValueError: [TypeError("'ObjectId' object is not iterable"), TypeError('vars() argument must have __dict__ attribute')]

Code snippet

# Any object which contains a value of type Mongo ObjectId

ObjectId('666f6f2d6261722d71757578')

Possible Solution

My workaround is to monkey patch openapi encoder. Ideally openapi should reuse json encoder of APIGatewayRestResolver, or allow plugging in our own function.

from bson import ObjectId
from aws_lambda_powertools.event_handler.openapi.encoders import ENCODERS_BY_TYPE
ENCODERS_BY_TYPE[ObjectId] = lambda o: str(o)

Steps to Reproduce

Serialize an object which contains Mongo ObjectId

ObjectId('666f6f2d6261722d71757578')

Powertools for AWS Lambda (Python) version

latest

AWS Lambda function runtime

3.8

Packaging format used

PyPi

Debugging logs

No response

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

Status

Shipped

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions