diff --git a/aws_lambda_powertools/event_handler/api_gateway.py b/aws_lambda_powertools/event_handler/api_gateway.py index 8e4ea866dd1..5d57c645b27 100644 --- a/aws_lambda_powertools/event_handler/api_gateway.py +++ b/aws_lambda_powertools/event_handler/api_gateway.py @@ -26,7 +26,7 @@ _DYNAMIC_ROUTE_PATTERN = r"(<\w+>)" _SAFE_URI = "-._~()'!*:@,;" # https://www.ietf.org/rfc/rfc3986.txt # API GW/ALB decode non-safe URI chars; we must support them too -_UNSAFE_URI = "%<>\[\]{}|^" # noqa: W605 +_UNSAFE_URI = "%<> \[\]{}|^" # noqa: W605 _NAMED_GROUP_BOUNDARY_PATTERN = fr"(?P\1[{_SAFE_URI}{_UNSAFE_URI}\\w]+)" diff --git a/tests/functional/event_handler/test_api_gateway.py b/tests/functional/event_handler/test_api_gateway.py index c21cd352961..9b5835c8b20 100644 --- a/tests/functional/event_handler/test_api_gateway.py +++ b/tests/functional/event_handler/test_api_gateway.py @@ -715,6 +715,42 @@ def get_network_account(account_id: str, network_id: str): app.resolve(event, {}) +def test_similar_dynamic_routes_with_whitespaces(): + # GIVEN + app = ApiGatewayResolver() + event = deepcopy(LOAD_GW_EVENT) + + # WHEN + # r'^/accounts/(?P\\w+\\b)$' # noqa: E800 + @app.get("/accounts/") + def get_account(account_id: str): + assert account_id == "single account" + + # r'^/accounts/(?P\\w+\\b)/source_networks$' # noqa: E800 + @app.get("/accounts//source_networks") + def get_account_networks(account_id: str): + assert account_id == "nested account" + + # r'^/accounts/(?P\\w+\\b)/source_networks/(?P\\w+\\b)$' # noqa: E800 + @app.get("/accounts//source_networks/") + def get_network_account(account_id: str, network_id: str): + assert account_id == "nested account" + assert network_id == "network 123" + + # THEN + event["resource"] = "/accounts/{account_id}" + event["path"] = "/accounts/single account" + assert app.resolve(event, {})["statusCode"] == 200 + + event["resource"] = "/accounts/{account_id}/source_networks" + event["path"] = "/accounts/nested account/source_networks" + assert app.resolve(event, {})["statusCode"] == 200 + + event["resource"] = "/accounts/{account_id}/source_networks/{network_id}" + event["path"] = "/accounts/nested account/source_networks/network 123" + assert app.resolve(event, {})["statusCode"] == 200 + + @pytest.mark.parametrize( "req", [