Skip to content

feat(apigateway): introduce specialized routers for typing #1824

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
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
31 changes: 31 additions & 0 deletions aws_lambda_powertools/event_handler/router.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from aws_lambda_powertools.event_handler.api_gateway import Router
from aws_lambda_powertools.utilities.data_classes import (
ALBEvent,
APIGatewayProxyEvent,
APIGatewayProxyEventV2,
LambdaFunctionUrlEvent,
)


class APIGatewayRouter(Router):
"""Specialized Router class that exposes current_event as an APIGatewayProxyEvent"""

current_event: APIGatewayProxyEvent


class APIGatewayHttpRouter(Router):
"""Specialized Router class that exposes current_event as an APIGatewayProxyEventV2"""

current_event: APIGatewayProxyEventV2


class LambdaFunctionUrlRouter(Router):
"""Specialized Router class that exposes current_event as a LambdaFunctionUrlEvent"""

current_event: LambdaFunctionUrlEvent


class ALBRouter(Router):
"""Specialized Router class that exposes current_event as an ALBEvent"""

current_event: ALBEvent
15 changes: 15 additions & 0 deletions docs/core/event_handler/api_gateway.md
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,21 @@ When necessary, you can set a prefix when including a router object. This means
--8<-- "examples/event_handler_rest/src/split_route_prefix_module.py"
```

#### Specialized router types

You can use specialized router classes according to the type of event that you are resolving. This way you'll get type hints from your IDE as you access the `current_event` property.

| Router | Resolver | `current_event` type |
|-------------------------|---------------------------|------------------------|
| APIGatewayRouter | APIGatewayRestResolver | APIGatewayProxyEvent |
| APIGatewayHttpRouter | APIGatewayHttpResolver | APIGatewayProxyEventV2 |
| ALBRouter | ALBResolver | ALBEvent |
| LambdaFunctionUrlRouter | LambdaFunctionUrlResolver | LambdaFunctionUrlEvent |

```python hl_lines="1 5 9"
--8<-- "examples/event_handler_rest/src/split_route_specialized_router.py"
```

#### Sharing contextual data

You can use `append_context` when you want to share data between your App and Router instances. Any data you share will be available via the `context` dictionary available in your App or Router context.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from aws_lambda_powertools.event_handler import APIGatewayRestResolver
from aws_lambda_powertools.event_handler.router import APIGatewayRouter

app = APIGatewayRestResolver()
router = APIGatewayRouter()


@router.get("/me")
def get_self():
# router.current_event is a APIGatewayProxyEvent
account_id = router.current_event.request_context.account_id

return {"account_id": account_id}


app.include_router(router)


def lambda_handler(event, context):
return app.resolve(event, context)
76 changes: 76 additions & 0 deletions tests/functional/event_handler/test_router.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
from aws_lambda_powertools.event_handler import (
ALBResolver,
APIGatewayHttpResolver,
APIGatewayRestResolver,
LambdaFunctionUrlResolver,
Response,
)
from aws_lambda_powertools.event_handler.router import (
ALBRouter,
APIGatewayHttpRouter,
APIGatewayRouter,
LambdaFunctionUrlRouter,
)
from aws_lambda_powertools.utilities.data_classes import (
ALBEvent,
APIGatewayProxyEvent,
APIGatewayProxyEventV2,
LambdaFunctionUrlEvent,
)
from tests.functional.utils import load_event


def test_alb_router_event_type():
app = ALBResolver()
router = ALBRouter()

@router.route(rule="/lambda", method=["GET"])
def foo():
assert type(router.current_event) is ALBEvent
return Response(status_code=200, body="routed")

app.include_router(router)
result = app(load_event("albEvent.json"), {})
assert result["body"] == "routed"


def test_apigateway_router_event_type():
app = APIGatewayRestResolver()
router = APIGatewayRouter()

@router.route(rule="/my/path", method=["GET"])
def foo():
assert type(router.current_event) is APIGatewayProxyEvent
return Response(status_code=200, body="routed")

app.include_router(router)
result = app(load_event("apiGatewayProxyEvent.json"), {})
assert result["body"] == "routed"


def test_apigatewayhttp_router_event_type():
app = APIGatewayHttpResolver()
router = APIGatewayHttpRouter()

@router.route(rule="/my/path", method=["POST"])
def foo():
assert type(router.current_event) is APIGatewayProxyEventV2
return Response(status_code=200, body="routed")

app.include_router(router)
result = app(load_event("apiGatewayProxyV2Event.json"), {})
assert result["body"] == "routed"


def test_lambda_function_url_router_event_type():
app = LambdaFunctionUrlResolver()
router = LambdaFunctionUrlRouter()

@router.route(rule="/", method=["GET"])
def foo():
assert type(router.current_event) is LambdaFunctionUrlEvent
return Response(status_code=200, body="routed")

app.include_router(router)
result = app(load_event("lambdaFunctionUrlEvent.json"), {})
assert result["body"] == "routed"