Skip to content

Commit dd0f1ad

Browse files
committed
allowed a new deserializer for parser the body
1 parent 5c896db commit dd0f1ad

File tree

2 files changed

+39
-7
lines changed

2 files changed

+39
-7
lines changed

aws_lambda_powertools/event_handler/api_gateway.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1575,6 +1575,7 @@ def __init__(
15751575
strip_prefixes: list[str | Pattern] | None = None,
15761576
enable_validation: bool = False,
15771577
response_validation_error_http_code: HTTPStatus | int | None = None,
1578+
deserializer: Callable[[str], dict] | None = None,
15781579
):
15791580
"""
15801581
Parameters
@@ -1596,6 +1597,9 @@ def __init__(
15961597
Enables validation of the request body against the route schema, by default False.
15971598
response_validation_error_http_code
15981599
Sets the returned status code if response is not validated. enable_validation must be True.
1600+
deserializer: Callable[[str], dict], optional
1601+
function to deserialize `str`, `bytes`, `bytearray` containing a JSON document to a Python `dict`,
1602+
by default json.loads
15991603
"""
16001604
self._proxy_type = proxy_type
16011605
self._dynamic_routes: list[Route] = []
@@ -1621,6 +1625,7 @@ def __init__(
16211625

16221626
# Allow for a custom serializer or a concise json serialization
16231627
self._serializer = serializer or partial(json.dumps, separators=(",", ":"), cls=Encoder)
1628+
self._deserializer = deserializer
16241629

16251630
if self._enable_validation:
16261631
from aws_lambda_powertools.event_handler.middlewares.openapi_validation import OpenAPIValidationMiddleware
@@ -2431,24 +2436,24 @@ def _to_proxy_event(self, event: dict) -> BaseProxyEvent: # noqa: PLR0911 # ig
24312436
"""Convert the event dict to the corresponding data class"""
24322437
if self._proxy_type == ProxyEventType.APIGatewayProxyEvent:
24332438
logger.debug("Converting event to API Gateway REST API contract")
2434-
return APIGatewayProxyEvent(event)
2439+
return APIGatewayProxyEvent(event, self._deserializer)
24352440
if self._proxy_type == ProxyEventType.APIGatewayProxyEventV2:
24362441
logger.debug("Converting event to API Gateway HTTP API contract")
2437-
return APIGatewayProxyEventV2(event)
2442+
return APIGatewayProxyEventV2(event, self._deserializer)
24382443
if self._proxy_type == ProxyEventType.BedrockAgentEvent:
24392444
logger.debug("Converting event to Bedrock Agent contract")
2440-
return BedrockAgentEvent(event)
2445+
return BedrockAgentEvent(event, self._deserializer)
24412446
if self._proxy_type == ProxyEventType.LambdaFunctionUrlEvent:
24422447
logger.debug("Converting event to Lambda Function URL contract")
2443-
return LambdaFunctionUrlEvent(event)
2448+
return LambdaFunctionUrlEvent(event, self._deserializer)
24442449
if self._proxy_type == ProxyEventType.VPCLatticeEvent:
24452450
logger.debug("Converting event to VPC Lattice contract")
2446-
return VPCLatticeEvent(event)
2451+
return VPCLatticeEvent(event, self._deserializer)
24472452
if self._proxy_type == ProxyEventType.VPCLatticeEventV2:
24482453
logger.debug("Converting event to VPC LatticeV2 contract")
2449-
return VPCLatticeEventV2(event)
2454+
return VPCLatticeEventV2(event, self._deserializer)
24502455
logger.debug("Converting event to ALB contract")
2451-
return ALBEvent(event)
2456+
return ALBEvent(event, self._deserializer)
24522457

24532458
def _resolve(self) -> ResponseBuilder:
24542459
"""Resolves the response or return the not found response"""
@@ -2865,6 +2870,7 @@ def __init__(
28652870
strip_prefixes: list[str | Pattern] | None = None,
28662871
enable_validation: bool = False,
28672872
response_validation_error_http_code: HTTPStatus | int | None = None,
2873+
deserializer: Callable[[str], dict] | None = None,
28682874
):
28692875
"""Amazon API Gateway REST and HTTP API v1 payload resolver"""
28702876
super().__init__(
@@ -2875,6 +2881,7 @@ def __init__(
28752881
strip_prefixes,
28762882
enable_validation,
28772883
response_validation_error_http_code,
2884+
deserializer,
28782885
)
28792886

28802887
def _get_base_path(self) -> str:

tests/functional/event_handler/_pydantic/test_api_gateway.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
from __future__ import annotations
22

3+
import json
4+
from decimal import Decimal
5+
from functools import partial
6+
37
from pydantic import BaseModel
48

59
from aws_lambda_powertools.event_handler import content_types
@@ -80,3 +84,24 @@ def get_lambda(param: int): ...
8084
assert result["statusCode"] == 422
8185
assert result["multiValueHeaders"]["Content-Type"] == [content_types.APPLICATION_JSON]
8286
assert "missing" in result["body"]
87+
88+
89+
def test_api_gateway_resolver_numeric_value():
90+
# GIVEN a basic API Gateway resolver
91+
app = ApiGatewayResolver(deserializer=partial(json.loads, parse_float=Decimal))
92+
93+
@app.post("/my/path")
94+
def test_handler():
95+
return app.current_event.json_body
96+
97+
# WHEN calling the event handler
98+
event = {}
99+
event.update(LOAD_GW_EVENT)
100+
event["body"] = '{"amount": 2.2999999999999998}'
101+
event["httpMethod"] = "POST"
102+
103+
result = app(event, {})
104+
# THEN process event correctly
105+
assert result["statusCode"] == 200
106+
assert result["multiValueHeaders"]["Content-Type"] == [content_types.APPLICATION_JSON]
107+
assert result["body"] == '{"amount":"2.2999999999999998"}'

0 commit comments

Comments
 (0)