Skip to content
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
33 changes: 31 additions & 2 deletions aws_lambda_powertools/event_handler/api_gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
DEFAULT_OPENAPI_RESPONSE_DESCRIPTION,
DEFAULT_OPENAPI_TITLE,
DEFAULT_OPENAPI_VERSION,
DEFAULT_STATUS_CODE,
)
from aws_lambda_powertools.event_handler.openapi.exceptions import (
RequestUnsupportedContentType,
Expand Down Expand Up @@ -283,7 +284,7 @@ class BedrockResponse(Generic[ResponseT]):
def __init__(
self,
body: Any = None,
status_code: int = 200,
status_code: int = DEFAULT_STATUS_CODE,
content_type: str = DEFAULT_CONTENT_TYPE,
session_attributes: dict[str, Any] | None = None,
prompt_session_attributes: dict[str, Any] | None = None,
Expand Down Expand Up @@ -387,6 +388,7 @@ def __init__(
deprecated: bool = False,
enable_validation: bool | None = None,
custom_response_validation_http_code: HTTPStatus | None = None,
status_code: int = DEFAULT_STATUS_CODE,
middlewares: list[Callable[..., Response]] | None = None,
):
"""
Expand Down Expand Up @@ -432,6 +434,9 @@ def __init__(
Enable or disable validation for this specific route. If None, inherits from resolver setting.
custom_response_validation_http_code: int | HTTPStatus | None, optional
Whether to have custom http status code for this route if response validation fails
status_code: int
The default HTTP status code for successful responses. Used in both the OpenAPI schema
and the actual response when the handler returns a dict. Defaults to 200.
middlewares: list[Callable[..., Response]] | None
The list of route middlewares to be called in order.
"""
Expand Down Expand Up @@ -471,6 +476,7 @@ def __init__(
self._body_field: ModelField | None = None

self.custom_response_validation_http_code = custom_response_validation_http_code
self.status_code = status_code

# Cache whether this route's handler declares Depends() parameters
self._has_dependencies: bool | None = None
Expand Down Expand Up @@ -664,6 +670,7 @@ def _get_openapi_path(
response_description=self.response_description,
body_field=self.body_field,
custom_response_validation_http_code=self.custom_response_validation_http_code,
status_code=self.status_code,
dependant=dependant,
operation_ids=operation_ids,
model_name_map=model_name_map,
Expand Down Expand Up @@ -820,6 +827,7 @@ def route(
deprecated: bool = False,
enable_validation: bool | None = None,
custom_response_validation_http_code: int | HTTPStatus | None = None,
status_code: int = DEFAULT_STATUS_CODE,
middlewares: list[Callable[..., Any]] | None = None,
) -> Callable[[AnyCallableT], AnyCallableT]:
raise NotImplementedError()
Expand Down Expand Up @@ -883,6 +891,7 @@ def get(
deprecated: bool = False,
enable_validation: bool | None = None,
custom_response_validation_http_code: int | HTTPStatus | None = None,
status_code: int = DEFAULT_STATUS_CODE,
middlewares: list[Callable[..., Any]] | None = None,
) -> Callable[[AnyCallableT], AnyCallableT]:
"""Get route decorator with GET `method`
Expand Down Expand Up @@ -925,6 +934,7 @@ def lambda_handler(event, context):
deprecated,
enable_validation,
custom_response_validation_http_code,
status_code,
middlewares,
)

Expand All @@ -946,6 +956,7 @@ def post(
deprecated: bool = False,
enable_validation: bool | None = None,
custom_response_validation_http_code: int | HTTPStatus | None = None,
status_code: int = DEFAULT_STATUS_CODE,
middlewares: list[Callable[..., Any]] | None = None,
) -> Callable[[AnyCallableT], AnyCallableT]:
"""Post route decorator with POST `method`
Expand Down Expand Up @@ -989,6 +1000,7 @@ def lambda_handler(event, context):
deprecated,
enable_validation,
custom_response_validation_http_code,
status_code,
middlewares,
)

Expand All @@ -1010,6 +1022,7 @@ def put(
deprecated: bool = False,
enable_validation: bool | None = None,
custom_response_validation_http_code: int | HTTPStatus | None = None,
status_code: int = DEFAULT_STATUS_CODE,
middlewares: list[Callable[..., Any]] | None = None,
) -> Callable[[AnyCallableT], AnyCallableT]:
"""Put route decorator with PUT `method`
Expand Down Expand Up @@ -1053,6 +1066,7 @@ def lambda_handler(event, context):
deprecated,
enable_validation,
custom_response_validation_http_code,
status_code,
middlewares,
)

Expand All @@ -1074,6 +1088,7 @@ def delete(
deprecated: bool = False,
enable_validation: bool | None = None,
custom_response_validation_http_code: int | HTTPStatus | None = None,
status_code: int = DEFAULT_STATUS_CODE,
middlewares: list[Callable[..., Any]] | None = None,
) -> Callable[[AnyCallableT], AnyCallableT]:
"""Delete route decorator with DELETE `method`
Expand Down Expand Up @@ -1116,6 +1131,7 @@ def lambda_handler(event, context):
deprecated,
enable_validation,
custom_response_validation_http_code,
status_code,
middlewares,
)

Expand All @@ -1137,6 +1153,7 @@ def patch(
deprecated: bool = False,
enable_validation: bool | None = None,
custom_response_validation_http_code: int | HTTPStatus | None = None,
status_code: int = DEFAULT_STATUS_CODE,
middlewares: list[Callable] | None = None,
) -> Callable[[AnyCallableT], AnyCallableT]:
"""Patch route decorator with PATCH `method`
Expand Down Expand Up @@ -1182,6 +1199,7 @@ def lambda_handler(event, context):
deprecated,
enable_validation,
custom_response_validation_http_code,
status_code,
middlewares,
)

Expand All @@ -1203,6 +1221,7 @@ def head(
deprecated: bool = False,
enable_validation: bool | None = None,
custom_response_validation_http_code: int | HTTPStatus | None = None,
status_code: int = DEFAULT_STATUS_CODE,
middlewares: list[Callable] | None = None,
) -> Callable[[AnyCallableT], AnyCallableT]:
"""Head route decorator with HEAD `method`
Expand Down Expand Up @@ -1247,6 +1266,7 @@ def lambda_handler(event, context):
deprecated,
enable_validation,
custom_response_validation_http_code,
status_code,
middlewares,
)

Expand Down Expand Up @@ -2357,6 +2377,7 @@ def route(
deprecated: bool = False,
enable_validation: bool | None = None,
custom_response_validation_http_code: int | HTTPStatus | None = None,
status_code: int = DEFAULT_STATUS_CODE,
middlewares: list[Callable[..., Any]] | None = None,
) -> Callable[[AnyCallableT], AnyCallableT]:
"""Route decorator includes parameter `method`"""
Expand Down Expand Up @@ -2392,6 +2413,7 @@ def register_resolver(func: AnyCallableT) -> AnyCallableT:
deprecated,
enable_validation,
custom_response_validation_http_code,
status_code,
middlewares,
)

Expand Down Expand Up @@ -2779,12 +2801,15 @@ def _to_response(self, result: dict | tuple | Response | BedrockResponse) -> Res
- tuple[dict, int]: Same dict handling as above but with the option of including a status code
- Response: returned as is, and allows for more flexibility
"""
status_code = HTTPStatus.OK
if isinstance(result, (Response, BedrockResponse)):
return result
elif isinstance(result, tuple) and len(result) == 2:
# Unpack result dict and status code from tuple
result, status_code = result
else:
# Use the route's status_code if available, otherwise default to 200
route: Route | None = self.context.get("_route")
status_code = route.status_code if route else HTTPStatus.OK

logger.debug("Simple response detected, serializing return before constructing final response")
return Response(
Expand Down Expand Up @@ -2903,6 +2928,7 @@ def route(
deprecated: bool = False,
enable_validation: bool | None = None,
custom_response_validation_http_code: int | HTTPStatus | None = None,
status_code: int = DEFAULT_STATUS_CODE,
middlewares: list[Callable[..., Any]] | None = None,
) -> Callable[[AnyCallableT], AnyCallableT]:
def register_route(func: AnyCallableT) -> AnyCallableT:
Expand Down Expand Up @@ -2931,6 +2957,7 @@ def register_route(func: AnyCallableT) -> AnyCallableT:
deprecated,
enable_validation,
custom_response_validation_http_code,
status_code,
)

# Collate Middleware for routes
Expand Down Expand Up @@ -3000,6 +3027,7 @@ def route(
deprecated: bool = False,
enable_validation: bool | None = None,
custom_response_validation_http_code: int | HTTPStatus | None = None,
status_code: int = DEFAULT_STATUS_CODE,
middlewares: list[Callable[..., Any]] | None = None,
) -> Callable[[AnyCallableT], AnyCallableT]:
# NOTE: see #1552 for more context.
Expand All @@ -3021,6 +3049,7 @@ def route(
deprecated,
enable_validation,
custom_response_validation_http_code,
status_code,
middlewares,
)

Expand Down
11 changes: 11 additions & 0 deletions aws_lambda_powertools/event_handler/bedrock_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
DEFAULT_API_VERSION,
DEFAULT_OPENAPI_RESPONSE_DESCRIPTION,
DEFAULT_OPENAPI_VERSION,
DEFAULT_STATUS_CODE,
)

if TYPE_CHECKING:
Expand Down Expand Up @@ -129,6 +130,7 @@ def get( # type: ignore[override]
deprecated: bool = False,
enable_validation: bool | None = None,
custom_response_validation_http_code: int | HTTPStatus | None = None,
status_code: int = DEFAULT_STATUS_CODE,
middlewares: list[Callable[..., Any]] | None = None,
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
security = None
Expand All @@ -150,6 +152,7 @@ def get( # type: ignore[override]
deprecated,
enable_validation,
custom_response_validation_http_code,
status_code,
middlewares,
)

Expand All @@ -172,6 +175,7 @@ def post( # type: ignore[override]
deprecated: bool = False,
enable_validation: bool | None = None,
custom_response_validation_http_code: int | HTTPStatus | None = None,
status_code: int = DEFAULT_STATUS_CODE,
middlewares: list[Callable[..., Any]] | None = None,
):
security = None
Expand All @@ -193,6 +197,7 @@ def post( # type: ignore[override]
deprecated,
enable_validation,
custom_response_validation_http_code,
status_code,
middlewares,
)

Expand All @@ -215,6 +220,7 @@ def put( # type: ignore[override]
deprecated: bool = False,
enable_validation: bool | None = None,
custom_response_validation_http_code: int | HTTPStatus | None = None,
status_code: int = DEFAULT_STATUS_CODE,
middlewares: list[Callable[..., Any]] | None = None,
):
security = None
Expand All @@ -236,6 +242,7 @@ def put( # type: ignore[override]
deprecated,
enable_validation,
custom_response_validation_http_code,
status_code,
middlewares,
)

Expand All @@ -258,6 +265,7 @@ def patch( # type: ignore[override]
deprecated: bool = False,
enable_validation: bool | None = None,
custom_response_validation_http_code: int | HTTPStatus | None = None,
status_code: int = DEFAULT_STATUS_CODE,
middlewares: list[Callable] | None = None,
):
security = None
Expand All @@ -279,6 +287,7 @@ def patch( # type: ignore[override]
deprecated,
enable_validation,
custom_response_validation_http_code,
status_code,
middlewares,
)

Expand All @@ -301,6 +310,7 @@ def delete( # type: ignore[override]
deprecated: bool = False,
enable_validation: bool | None = None,
custom_response_validation_http_code: int | HTTPStatus | None = None,
status_code: int = DEFAULT_STATUS_CODE,
middlewares: list[Callable[..., Any]] | None = None,
):
security = None
Expand All @@ -322,6 +332,7 @@ def delete( # type: ignore[override]
deprecated,
enable_validation,
custom_response_validation_http_code,
status_code,
middlewares,
)

Expand Down
1 change: 1 addition & 0 deletions aws_lambda_powertools/event_handler/openapi/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
DEFAULT_OPENAPI_TITLE = "Powertools for AWS Lambda (Python) API"
DEFAULT_CONTENT_TYPE = "application/json"
DEFAULT_OPENAPI_RESPONSE_DESCRIPTION = "Successful Response"
DEFAULT_STATUS_CODE = 200
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
from aws_lambda_powertools.event_handler.openapi.constants import (
DEFAULT_CONTENT_TYPE,
DEFAULT_OPENAPI_RESPONSE_DESCRIPTION,
DEFAULT_STATUS_CODE,
)


Expand All @@ -54,6 +55,7 @@
response_description: str | None,
body_field: ModelField | None,
custom_response_validation_http_code: HTTPStatus | None,
status_code: int = DEFAULT_STATUS_CODE,
dependant: Dependant,
operation_ids: set[str],
model_name_map: dict[TypeModelOrEnum, str],
Expand Down Expand Up @@ -108,6 +110,7 @@
responses=responses,
response_description=response_description,
custom_response_validation_http_code=custom_response_validation_http_code,
status_code=status_code,
dependant=dependant,
model_name_map=model_name_map,
field_mapping=field_mapping,
Expand Down Expand Up @@ -220,6 +223,7 @@
responses: dict[int, OpenAPIResponse] | None,
response_description: str | None,
custom_response_validation_http_code: HTTPStatus | None,
status_code: int = DEFAULT_STATUS_CODE,
dependant: Dependant,
model_name_map: dict[TypeModelOrEnum, str],
field_mapping: dict[tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue],
Expand All @@ -237,9 +241,9 @@
)

if responses:
for status_code in list(responses):
operation_responses[status_code] = _build_custom_response(
response=copy.deepcopy(responses[status_code]),
for resp_code in list(responses):

Check warning on line 244 in aws_lambda_powertools/event_handler/openapi/schema_generator.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this unnecessary `list()` call on an already iterable object.

See more on https://sonarcloud.io/project/issues?id=aws-powertools_powertools-lambda-python&issues=AZ1r75FbAo3DRkjyGtov&open=AZ1r75FbAo3DRkjyGtov&pullRequest=8130
operation_responses[resp_code] = _build_custom_response(
response=copy.deepcopy(responses[resp_code]),
dependant=dependant,
model_name_map=model_name_map,
field_mapping=field_mapping,
Expand All @@ -251,7 +255,7 @@
field_mapping=field_mapping,
)

operation_responses[200] = {
operation_responses[status_code] = {
"description": response_description or DEFAULT_OPENAPI_RESPONSE_DESCRIPTION,
"content": {DEFAULT_CONTENT_TYPE: response_schema},
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ Here's a breakdown of various customizable fields:
| `tags` | `List[str]` | Tags are a way to categorize and group endpoints within the API documentation. They can help organize the operations by resources or other heuristic. |
| `operation_id` | `str` | A unique identifier for the operation, which can be used for referencing this operation in documentation or code. This ID must be unique across all operations described in the API. |
| `include_in_schema` | `bool` | A boolean value that determines whether or not this operation should be included in the OpenAPI schema. Setting it to `False` can hide the endpoint from generated documentation and schema exports, which might be useful for private or experimental endpoints. |
| `deprecated` | `bool` | A boolean value that determines whether or not this operation should be marked as deprecated in the OpenAPI schema. |
| `deprecated` | `bool` | A boolean value that determines whether or not this operation should be marked as deprecated in the OpenAPI schema. |
| `status_code` | `int` | The default HTTP status code for successful responses. Defaults to `200`. This value is used both in the OpenAPI schema and as the actual response status code when the handler returns a dictionary or plain value (not a `Response` object or tuple). |
2 changes: 1 addition & 1 deletion docs/core/event_handler/openapi.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ To implement these customizations, include extra parameters when defining your r

=== "customizing_api_operations.py"

```python hl_lines="11-20"
```python hl_lines="11-20 29-36"
--8<-- "examples/event_handler_rest/src/customizing_api_operations.py"
```

Expand Down
Loading
Loading