From ce8ecb5f5bdbcc7144efa3ba217f6de58680d16d Mon Sep 17 00:00:00 2001 From: Tanbir Hossain Ramim <96797470+TanbirRamim@users.noreply.github.com> Date: Sun, 13 Sep 2026 02:09:51 +0200 Subject: [PATCH] fix(event_handler): match generic alias response models in OpenAPI schema Custom responses are deep-copied before resolving their model, and deepcopy returns a new object for generic aliases such as list[Model]. The identity check against response_extra_models never matched, so schema generation raised StopIteration. Compare by equality instead. Fixes #8450 --- .../event_handler/openapi/schema_generator.py | 2 +- .../_pydantic/test_openapi_responses.py | 37 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/aws_lambda_powertools/event_handler/openapi/schema_generator.py b/aws_lambda_powertools/event_handler/openapi/schema_generator.py index 096780996f9..0d3de7e1f8c 100644 --- a/aws_lambda_powertools/event_handler/openapi/schema_generator.py +++ b/aws_lambda_powertools/event_handler/openapi/schema_generator.py @@ -538,7 +538,7 @@ def _resolve_response_payload( model_payload_typed = cast(OpenAPIResponseContentModel, payload) return_field = next( filter( - lambda model: model.type_ is model_payload_typed["model"], + lambda model: model.type_ == model_payload_typed["model"], dependant.response_extra_models, ), ) diff --git a/tests/functional/event_handler/_pydantic/test_openapi_responses.py b/tests/functional/event_handler/_pydantic/test_openapi_responses.py index c00b4e00462..3ccb4a73c94 100644 --- a/tests/functional/event_handler/_pydantic/test_openapi_responses.py +++ b/tests/functional/event_handler/_pydantic/test_openapi_responses.py @@ -456,3 +456,40 @@ def patch(): assert 204 in schema.paths["/items"].put.responses assert 204 in schema.paths["/items"].delete.responses assert 202 in schema.paths["/items"].patch.responses + + +def test_openapi_custom_response_with_generic_alias_models(): + # GIVEN routes whose custom response models are generic aliases + app = APIGatewayRestResolver(enable_validation=True) + + class Item(BaseModel): + id: int + + @app.get( + "/items", + responses={200: {"description": "List of items", "content": {"application/json": {"model": list[Item]}}}}, + ) + def list_items() -> list[Item]: + return [] + + @app.get( + "/items/by-name", + responses={200: {"description": "Items by name", "content": {"application/json": {"model": dict[str, Item]}}}}, + ) + def items_by_name() -> dict[str, Item]: + return {} + + # WHEN we retrieve the OpenAPI schema + schema = app.get_openapi_schema() + + # THEN the list model should produce an array schema + list_response = schema.paths["/items"].get.responses[200] + assert list_response.description == "List of items" + list_schema = list_response.content["application/json"].schema_ + assert list_schema.type == "array" + assert list_schema.items.ref == "#/components/schemas/Item" + + # AND the dict model should produce an object schema + dict_schema = schema.paths["/items/by-name"].get.responses[200].content["application/json"].schema_ + assert dict_schema.type == "object" + assert dict_schema.additionalProperties.ref == "#/components/schemas/Item"