Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 19 additions & 6 deletions src/aws_durable_execution_sdk_python_testing/web/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
26 changes: 11 additions & 15 deletions tests/web/handlers_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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():
Expand Down Expand Up @@ -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():
Expand Down
Loading