Skip to content

fix(event_handler): Router prefix mismatch regression after Middleware feat #3302

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Nov 7, 2023
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
4 changes: 3 additions & 1 deletion aws_lambda_powertools/event_handler/api_gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -2008,6 +2008,7 @@ def include_router(self, router: "Router", prefix: Optional[str] = None) -> None
# use pointer to allow context clearance after event is processed e.g., resolve(evt, ctx)
router.context = self.context

# Iterate through the routes defined in the router to configure and apply middlewares for each route
for route, func in router._routes.items():
new_route = route

Expand All @@ -2017,7 +2018,8 @@ def include_router(self, router: "Router", prefix: Optional[str] = None) -> None
new_route = (rule, *route[1:])

# Middlewares are stored by route separately - must grab them to include
middlewares = router._routes_with_middleware.get(new_route)
# Middleware store the route without prefix, so we must not include prefix when grabbing
middlewares = router._routes_with_middleware.get(route)

# Need to use "type: ignore" here since mypy does not like a named parameter after
# tuple expansion since may cause duplicate named parameters in the function signature.
Expand Down
19 changes: 19 additions & 0 deletions tests/functional/event_handler/test_api_gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -1197,6 +1197,25 @@ def base():
assert result["multiValueHeaders"]["Content-Type"] == [content_types.APPLICATION_JSON]


def test_api_gateway_app_with_strip_prefix_and_route_prefix():
# GIVEN all routes are stripped from its version e.g., /v1
app = ApiGatewayResolver(strip_prefixes=["/v1"])
router = Router()

event = {"httpMethod": "GET", "path": "/v1/users/leandro", "resource": "/users"}

@router.get("<user_id>")
def base(user_id: str):
return {"user": user_id}

# WHEN a router is included prefixing all routes with "/users/"
app.include_router(router, prefix="/users/")
result = app(event, {})

# THEN route correctly to the registered route after stripping each prefix (global + router)
assert result["statusCode"] == 200


def test_api_gateway_app_router():
# GIVEN a Router with registered routes
app = ApiGatewayResolver()
Expand Down
28 changes: 28 additions & 0 deletions tests/functional/event_handler/test_api_middlewares.py
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,34 @@ def dummy_route():
assert result["statusCode"] == 200


def test_api_gateway_middleware_with_include_router_prefix():
# GIVEN an App and Router instance
app = ApiGatewayResolver()
router = Router()

def app_middleware(app: EventHandlerInstance, next_middleware: NextMiddleware):
# AND a variable injected into resolver context
app.append_context(injected="injected_value")
return next_middleware(app)

# WHEN we register a route with a middleware
@router.get("/path", middlewares=[app_middleware])
def dummy_route():
# THEN we should have access to the middleware's injected variable
assert app.context["injected"] == "injected_value"

return Response(status_code=200, body="works!")

# WHEN register the route with a prefix
app.include_router(router, prefix="/my")

# THEN resolving a request must execute the middleware
# and return a successful response http 200 status code
result = app(API_REST_EVENT, {})

assert result["statusCode"] == 200


@pytest.mark.parametrize(
"app, event",
[
Expand Down