Skip to content

fix(event_handler): allow responses and metadata when using Router #3514

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 3 commits into from
Dec 15, 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
9 changes: 6 additions & 3 deletions aws_lambda_powertools/event_handler/api_gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
validation_error_definition,
validation_error_response_definition,
)
from aws_lambda_powertools.event_handler.util import _FrozenDict
from aws_lambda_powertools.shared.cookies import Cookie
from aws_lambda_powertools.shared.functions import powertools_dev_is_set
from aws_lambda_powertools.shared.json_encoder import Encoder
Expand Down Expand Up @@ -2130,8 +2131,10 @@ def route(
middlewares: Optional[List[Callable[..., Any]]] = None,
):
def register_route(func: Callable):
# Convert methods to tuple. It needs to be hashable as its part of the self._routes dict key
# All dict keys needs to be hashable. So we'll need to do some conversions:
methods = (method,) if isinstance(method, str) else tuple(method)
frozen_responses = _FrozenDict(responses) if responses else None
frozen_tags = frozenset(tags) if tags else None

route_key = (
rule,
Expand All @@ -2141,9 +2144,9 @@ def register_route(func: Callable):
cache_control,
summary,
description,
responses,
frozen_responses,
response_description,
tags,
frozen_tags,
operation_id,
include_in_schema,
)
Expand Down
13 changes: 13 additions & 0 deletions aws_lambda_powertools/event_handler/util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class _FrozenDict(dict):
"""
A dictionary that can be used as a key in another dictionary.

This is needed because the default dict implementation is not hashable.
The only usage for this right now is to store dicts as part of the Router key.
The implementation only takes into consideration the keys of the dictionary.

MAINTENANCE: this is a temporary solution until we refactor the route key into a class.
"""

def __hash__(self):
return hash(frozenset(self.keys()))
34 changes: 33 additions & 1 deletion tests/functional/event_handler/test_openapi_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from pydantic import BaseModel

from aws_lambda_powertools.event_handler.api_gateway import APIGatewayRestResolver, Response
from aws_lambda_powertools.event_handler.api_gateway import APIGatewayRestResolver, Response, Router
from aws_lambda_powertools.event_handler.openapi.models import (
Example,
Parameter,
Expand Down Expand Up @@ -392,6 +392,38 @@ def secret():
assert len(schema.paths.keys()) == 0


def test_openapi_with_router_response():
router = Router()

@router.put("/example-resource", responses={200: {"description": "Custom response"}})
def handler():
pass

app = APIGatewayRestResolver(enable_validation=True)
app.include_router(router)

schema = app.get_openapi_schema()
put = schema.paths["/example-resource"].put
assert 200 in put.responses.keys()
assert put.responses[200].description == "Custom response"


def test_openapi_with_router_tags():
router = Router()

@router.put("/example-resource", tags=["Example"])
def handler():
pass

app = APIGatewayRestResolver(enable_validation=True)
app.include_router(router)

schema = app.get_openapi_schema()
tags = schema.paths["/example-resource"].put.tags
assert len(tags) == 1
assert tags[0].name == "Example"


def test_create_header():
header = _Header(convert_underscores=True)
assert header.convert_underscores is True
Expand Down