Description
The 1.18.0 release resolves the path regex greedy match problem in #520, but introduces a regression in the new regex pattern. To resolve the greedy match issue, #520 matches on the \w
character set and on the non-word boundary (\b
) to ensure trailing path components following the match aren't captured. Unfortunately, this change also prevents match of path values containing non-word characters. Email addresses, URL-encoded values, and RFC 4122 UUIDs no long match route rules, because @
, %
, and -
are not included in the \w
character match set.
Expected Behavior
APIGatewayResolver
route rules should match request path parameters containing @
, -
, and %
in addition to word characters. This was the matching behavior in the 1.17.x release.
Current Behavior
No routes are matched if a path parameter contains a non-word character.
Possible Solution
The _NAMED_GROUP_BOUNDARY_PATTERN
needs to be modified to include common non-word ASCII characters used in path components. Here's one possible pattern that seems to work while avoiding greedy capture:
r"(?P\1[-%@.:\\w]+)"
As shown in the REPL:
>>> import re
>>> from uuid import uuid4
>>> m = re.match("/api/v1/(?P<test>[-%@\\w]+)/items", f"/api/v1/{uuid4()}/items")
>>> m.groupdict()
{'test': '1f21c0c1-cd19-4775-8033-9e6244d54d79'}
>>> m = re.match("/api/v1/(?P<test>[-%@.:\\w]+)/items", f"/api/v1/user@example.com/items")
>>> m.groupdict()
{'test': 'user@example.com'}
Steps to Reproduce (for bugs)
The following should call the get_user_items()
function and print a Response
JSON object containing the items
object in the body. However, because the path parameter contains a non-word character, no route matches request path, and a 404 Response JSON object is printed instead.
from aws_lambda_powertools.event_handler.api_gateway import ApiGatewayResolver
api = ApiGatewayResolver()
@api.get("/api/v1/<user>/items")
def get_user_items(user):
return {"items": ["1", "2", "3"]}
def handler(event, context):
return api.resolve(event, context)
if __name__ == "__main__":
event = {
"httpMethod": "GET",
"path": "/api/v1/user@example.com/items"
}
print(handler(event, {}))
This works (albeit with the greedy match problem) in 1.17.x.
Environment
- Powertools version used: 1.18.0
- Packaging format (Layers, PyPi): PyPI
- AWS Lambda function runtime: 3.8