diff --git a/src/aws_durable_execution_sdk_python_testing/web/handlers.py b/src/aws_durable_execution_sdk_python_testing/web/handlers.py index 6db0b8a..2fee38e 100644 --- a/src/aws_durable_execution_sdk_python_testing/web/handlers.py +++ b/src/aws_durable_execution_sdk_python_testing/web/handlers.py @@ -91,11 +91,27 @@ def _parse_json_body(self, request: HTTPRequest) -> dict[str, Any]: dict: The parsed JSON data Raises: - InvalidParameterValueException: If the request body is empty or invalid JSON + InvalidParameterValueException: If the request body is empty """ if not request.body: msg = "Request body is required" raise InvalidParameterValueException(msg) + return self._parse_json_body_optional(request) + + def _parse_json_body_optional(self, request: HTTPRequest) -> dict[str, Any]: + """Parse JSON body from HTTP request with validation. + + Args: + request: The HTTP request containing the JSON body + + Returns: + dict: The parsed JSON data + + Raises: + InvalidParameterValueException: If the request body is invalid JSON + """ + if not request.body: + return {} # Handle both dict and bytes body types if isinstance(request.body, dict): @@ -690,7 +706,7 @@ def handle(self, parsed_route: Route, request: HTTPRequest) -> HTTPResponse: callback_route = cast(CallbackFailureRoute, parsed_route) callback_id: str = callback_route.callback_id - body_data: dict[str, Any] = self._parse_json_body(request) + body_data: dict[str, Any] = self._parse_json_body_optional(request) callback_request: SendDurableExecutionCallbackFailureRequest = ( SendDurableExecutionCallbackFailureRequest.from_dict( body_data, callback_id @@ -734,10 +750,7 @@ def handle(self, parsed_route: Route, request: HTTPRequest) -> HTTPResponse: HTTPResponse: The HTTP response to send to the client """ try: - # Parse request body for validation but heartbeat doesn't use the data - body_data: dict[str, Any] = self._parse_json_body(request) - SendDurableExecutionCallbackHeartbeatRequest.from_dict(body_data) - + # Heartbeat requests don't have a body, only callback_id from URL callback_route = cast(CallbackHeartbeatRoute, parsed_route) callback_id: str = callback_route.callback_id diff --git a/tests/web/handlers_test.py b/tests/web/handlers_test.py index d3217e5..bd8b5d4 100644 --- a/tests/web/handlers_test.py +++ b/tests/web/handlers_test.py @@ -2173,10 +2173,8 @@ def test_send_durable_execution_callback_failure_handler_empty_body(): ) response = handler.handle(callback_route, request) - # Handler returns 400 for empty body with AWS-compliant format - assert response.status_code == 400 - assert response.body["Type"] == "InvalidParameterValueException" - assert "Request body is required" in response.body["message"] + # Handler should accept empty body for failure requests + assert response.status_code == 200 def test_send_durable_execution_callback_heartbeat_handler(): @@ -2221,24 +2219,22 @@ def test_send_durable_execution_callback_heartbeat_handler_empty_body(): executor = Mock() handler = SendDurableExecutionCallbackHeartbeatHandler(executor) + base_route = Route.from_string( + "/2025-12-01/durable-execution-callbacks/test-id/heartbeat" + ) + callback_route = CallbackHeartbeatRoute.from_route(base_route) + request = HTTPRequest( method="POST", - path=Route.from_string( - "/2025-12-01/durable-execution-callbacks/test-id/heartbeat" - ), + path=callback_route, headers={}, query_params={}, body={}, ) - response = handler.handle( - Route.from_string("/2025-12-01/durable-execution-callbacks/test-id/heartbeat"), - request, - ) - # Handler returns 400 for empty body with AWS-compliant format - assert response.status_code == 400 - assert response.body["Type"] == "InvalidParameterValueException" - assert "Request body is required" in response.body["message"] + response = handler.handle(callback_route, request) + # Handler should accept empty body for heartbeat requests + assert response.status_code == 200 def test_health_handler():