Skip to content

Commit 5c34fb5

Browse files
Merge branch 'develop' into dependabot/pip/develop/dev-dependencies-113f34d9f4
2 parents 83853d1 + 2f1fbad commit 5c34fb5

File tree

8 files changed

+128
-70
lines changed

8 files changed

+128
-70
lines changed

.github/workflows/dependency-review.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,4 @@ jobs:
2222
- name: 'Checkout Repository'
2323
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
2424
- name: 'Dependency Review'
25-
uses: actions/dependency-review-action@3c4e3dcb1aa7874d2c16be7d79418e9b7efd6261 # v4.8.2
25+
uses: actions/dependency-review-action@05fe4576374b728f0c523d6a13d64c25081e0803 # v4.8.3

aws_lambda_powertools/event_handler/api_gateway.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
DEFAULT_OPENAPI_VERSION,
2828
)
2929
from aws_lambda_powertools.event_handler.openapi.exceptions import (
30+
RequestUnsupportedContentType,
3031
RequestValidationError,
3132
ResponseValidationError,
3233
SchemaValidationError,
@@ -2972,6 +2973,18 @@ def _call_exception_handler(self, exp: Exception, route: Route) -> ResponseBuild
29722973
route=route,
29732974
)
29742975

2976+
if isinstance(exp, RequestUnsupportedContentType):
2977+
errors = [{"loc": e["loc"], "type": e["type"]} for e in exp.errors()]
2978+
return self._response_builder_class(
2979+
response=Response(
2980+
status_code=HTTPStatus.UNSUPPORTED_MEDIA_TYPE,
2981+
content_type=content_types.APPLICATION_JSON,
2982+
body={"statusCode": HTTPStatus.UNSUPPORTED_MEDIA_TYPE, "detail": errors},
2983+
),
2984+
serializer=self._serializer,
2985+
route=route,
2986+
)
2987+
29752988
if isinstance(exp, ServiceError):
29762989
return self._response_builder_class(
29772990
response=Response(

aws_lambda_powertools/event_handler/middlewares/openapi_validation.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@
1919
)
2020
from aws_lambda_powertools.event_handler.openapi.dependant import is_scalar_field
2121
from aws_lambda_powertools.event_handler.openapi.encoders import jsonable_encoder
22-
from aws_lambda_powertools.event_handler.openapi.exceptions import RequestValidationError, ResponseValidationError
22+
from aws_lambda_powertools.event_handler.openapi.exceptions import (
23+
RequestUnsupportedContentType,
24+
RequestValidationError,
25+
ResponseValidationError,
26+
)
2327
from aws_lambda_powertools.event_handler.openapi.params import Param
2428

2529
if TYPE_CHECKING:
@@ -129,7 +133,18 @@ def _get_body(self, app: EventHandlerInstance) -> dict[str, Any]:
129133
return self._parse_form_data(app)
130134

131135
else:
132-
raise NotImplementedError("Only JSON body or Form() are supported")
136+
raise RequestUnsupportedContentType(
137+
"Only JSON body or Form() are supported",
138+
errors=[
139+
{
140+
"type": "unsupported_content_type",
141+
"loc": ("body",),
142+
"msg": "Only JSON body or Form() are supported",
143+
"input": {},
144+
"ctx": {},
145+
},
146+
],
147+
)
133148

134149
def _parse_json_data(self, app: EventHandlerInstance) -> dict[str, Any]:
135150
"""Parse JSON data from the request body."""

aws_lambda_powertools/event_handler/openapi/exceptions.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,13 @@ class SchemaValidationError(ValidationException):
4949

5050
class OpenAPIMergeError(Exception):
5151
"""Exception raised when there's a conflict during OpenAPI merge."""
52+
53+
54+
class RequestUnsupportedContentType(NotImplementedError, ValidationException):
55+
"""Exception raised when trying to read request body data, with unknown headers"""
56+
57+
# REVIEW: This inheritance is for backwards compatibility.
58+
# Just inherit from ValidationException in Powertools V4
59+
def __init__(self, msg: str, errors: Sequence[Any]) -> None:
60+
NotImplementedError.__init__(self, msg)
61+
ValidationException.__init__(self, errors)

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22
"name": "aws-lambda-powertools-python-e2e",
33
"version": "1.0.0",
44
"devDependencies": {
5-
"aws-cdk": "^2.1105.0"
5+
"aws-cdk": "^2.1106.0"
66
}
77
}

poetry.lock

Lines changed: 56 additions & 62 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/functional/event_handler/_pydantic/test_openapi_validation_middleware.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,32 @@ def handler(user: Model) -> Model:
715715
assert json.loads(result["body"]) == {"name": "John", "age": 30}
716716

717717

718+
def test_validate_unsupported_content_type_headers(gw_event):
719+
# GIVEN an APIGatewayRestResolver with validation enabled
720+
app = APIGatewayRestResolver(enable_validation=True)
721+
722+
class Model(BaseModel):
723+
name: str
724+
age: int
725+
726+
# WHEN a handler is defined with a body parameter
727+
# WHEN headers has unsupported content-type
728+
@app.post("/")
729+
def handler(user: Model) -> Model:
730+
return user
731+
732+
gw_event["httpMethod"] = "POST"
733+
gw_event["headers"] = {"Content-type": "text/fake-content-type"}
734+
gw_event["path"] = "/"
735+
gw_event["body"] = json.dumps({"name": "John", "age": 30})
736+
737+
# THEN the handler should return 415 (Unsupported Media Type)
738+
# THEN the body must have the "unsupported_content_type" error message
739+
result = app(gw_event, {})
740+
assert result["statusCode"] == 415
741+
assert "unsupported_content_type" in result["body"]
742+
743+
718744
def test_validate_body_param_with_invalid_date(gw_event):
719745
# GIVEN an APIGatewayRestResolver with validation enabled
720746
app = APIGatewayRestResolver(enable_validation=True)

0 commit comments

Comments
 (0)