wellapi 0.10.3__tar.gz → 0.10.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. {wellapi-0.10.3 → wellapi-0.10.4}/PKG-INFO +1 -1
  2. {wellapi-0.10.3 → wellapi-0.10.4}/pyproject.toml +1 -1
  3. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/routing.py +29 -25
  4. wellapi-0.10.4/tests/test_request_handler_body.py +39 -0
  5. {wellapi-0.10.3 → wellapi-0.10.4}/uv.lock +225 -225
  6. {wellapi-0.10.3 → wellapi-0.10.4}/.github/workflows/build.pipeline.yml +0 -0
  7. {wellapi-0.10.3 → wellapi-0.10.4}/.gitignore +0 -0
  8. {wellapi-0.10.3 → wellapi-0.10.4}/.python-version +0 -0
  9. {wellapi-0.10.3 → wellapi-0.10.4}/README.md +0 -0
  10. {wellapi-0.10.3 → wellapi-0.10.4}/docs/framework-usage.md +0 -0
  11. {wellapi-0.10.3 → wellapi-0.10.4}/docs/superpowers/plans/2026-05-29-otel-native-telemetry.md +0 -0
  12. {wellapi-0.10.3 → wellapi-0.10.4}/docs/superpowers/specs/2026-05-29-otel-native-telemetry-design.md +0 -0
  13. {wellapi-0.10.3 → wellapi-0.10.4}/docs/telemetry.md +0 -0
  14. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/__init__.py +0 -0
  15. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/__main__.py +0 -0
  16. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/applications.py +0 -0
  17. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/awsmodel.py +0 -0
  18. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/build/__init__.py +0 -0
  19. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/build/cdk.py +0 -0
  20. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/build/packager.py +0 -0
  21. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/cli/__init__.py +0 -0
  22. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/cli/main.py +0 -0
  23. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/convertors.py +0 -0
  24. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/datastructures.py +0 -0
  25. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/dependencies/__init__.py +0 -0
  26. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/dependencies/models.py +0 -0
  27. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/dependencies/utils.py +0 -0
  28. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/exception_handlers.py +0 -0
  29. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/exceptions.py +0 -0
  30. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/local/__init__.py +0 -0
  31. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/local/router.py +0 -0
  32. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/local/server.py +0 -0
  33. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/middleware/__init__.py +0 -0
  34. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/middleware/base.py +0 -0
  35. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/middleware/cors.py +0 -0
  36. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/middleware/error.py +0 -0
  37. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/middleware/exceptions.py +0 -0
  38. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/middleware/main.py +0 -0
  39. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/models.py +0 -0
  40. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/openapi/__init__.py +0 -0
  41. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/openapi/docs.py +0 -0
  42. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/openapi/models.py +0 -0
  43. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/openapi/security_model.py +0 -0
  44. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/openapi/utils.py +0 -0
  45. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/params.py +0 -0
  46. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/security.py +0 -0
  47. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/telemetry/__init__.py +0 -0
  48. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/telemetry/attributes.py +0 -0
  49. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/telemetry/config.py +0 -0
  50. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/telemetry/flush.py +0 -0
  51. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/telemetry/middleware.py +0 -0
  52. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/testclient.py +0 -0
  53. {wellapi-0.10.3 → wellapi-0.10.4}/src/wellapi/utils.py +0 -0
  54. {wellapi-0.10.3 → wellapi-0.10.4}/tests/conftest.py +0 -0
  55. {wellapi-0.10.3 → wellapi-0.10.4}/tests/telemetry/__init__.py +0 -0
  56. {wellapi-0.10.3 → wellapi-0.10.4}/tests/telemetry/test_applications.py +0 -0
  57. {wellapi-0.10.3 → wellapi-0.10.4}/tests/telemetry/test_attributes.py +0 -0
  58. {wellapi-0.10.3 → wellapi-0.10.4}/tests/telemetry/test_config.py +0 -0
  59. {wellapi-0.10.3 → wellapi-0.10.4}/tests/telemetry/test_flush.py +0 -0
  60. {wellapi-0.10.3 → wellapi-0.10.4}/tests/telemetry/test_middleware.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wellapi
3
- Version: 0.10.3
3
+ Version: 0.10.4
4
4
  Summary: A simple web framework for aws lambda
5
5
  Author-email: romayuhym <romayuhym@gmail.com>
6
6
  Requires-Python: >=3.12
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "wellapi"
3
- version = "0.10.3"
3
+ version = "0.10.4"
4
4
  description = "A simple web framework for aws lambda"
5
5
  readme = "README.md"
6
6
  authors = [
@@ -9,7 +9,7 @@ from pydantic.main import IncEx
9
9
  from wellapi.convertors import CONVERTOR_TYPES
10
10
  from wellapi.datastructures import Default, DefaultPlaceholder
11
11
  from wellapi.dependencies.models import Dependant, ModelField
12
- from wellapi.dependencies.utils import solve_dependencies
12
+ from wellapi.dependencies.utils import get_flat_dependant, solve_dependencies
13
13
  from wellapi.exceptions import (
14
14
  HTTPException,
15
15
  RequestValidationError,
@@ -100,33 +100,37 @@ def get_request_handler(
100
100
  else:
101
101
  actual_response_class = response_class
102
102
 
103
+ has_body_params = bool(get_flat_dependant(dependant).body_params)
104
+
103
105
  @functools.wraps(dependant.call)
104
106
  def app(request: RequestAPIGateway) -> ResponseAPIGateway:
105
107
  response: ResponseAPIGateway | None = None
106
- try:
107
- body: Any = request.json()
108
- except json.JSONDecodeError as e:
109
- validation_error = RequestValidationError(
110
- [
111
- {
112
- "type": "json_invalid",
113
- "loc": ("body", e.pos),
114
- "msg": "JSON decode error",
115
- "input": {},
116
- "ctx": {"error": e.msg},
117
- }
118
- ],
119
- body=e.doc,
120
- )
121
- raise validation_error from e
122
- except HTTPException:
123
- # If a middleware raises an HTTPException, it should be raised again
124
- raise
125
- except Exception as e:
126
- http_error = HTTPException(
127
- status_code=400, detail="There was an error parsing the body"
128
- )
129
- raise http_error from e
108
+ body: Any = None
109
+ if has_body_params:
110
+ try:
111
+ body = request.json()
112
+ except json.JSONDecodeError as e:
113
+ validation_error = RequestValidationError(
114
+ [
115
+ {
116
+ "type": "json_invalid",
117
+ "loc": ("body", e.pos),
118
+ "msg": "JSON decode error",
119
+ "input": {},
120
+ "ctx": {"error": e.msg},
121
+ }
122
+ ],
123
+ body=e.doc,
124
+ )
125
+ raise validation_error from e
126
+ except HTTPException:
127
+ # If a middleware raises an HTTPException, it should be raised again
128
+ raise
129
+ except Exception as e:
130
+ http_error = HTTPException(
131
+ status_code=400, detail="There was an error parsing the body"
132
+ )
133
+ raise http_error from e
130
134
  errors: list[Any] = []
131
135
  solved_result = solve_dependencies(
132
136
  request=request,
@@ -0,0 +1,39 @@
1
+ """Non-JSON request bodies must reach handlers that declare no body params."""
2
+
3
+ from typing import Annotated
4
+
5
+ import pytest
6
+
7
+ from wellapi import Body, WellApi
8
+ from wellapi.exceptions import RequestValidationError
9
+ from wellapi.models import RequestAPIGateway
10
+
11
+
12
+ def _make_request(api_gateway_event, body: str) -> RequestAPIGateway:
13
+ event = api_gateway_event | {"httpMethod": "POST", "body": body}
14
+ return RequestAPIGateway.create_request_from_event(event)
15
+
16
+
17
+ def test_non_json_body_reaches_handler_without_body_params(api_gateway_event):
18
+ app = WellApi()
19
+
20
+ @app.post("/relay")
21
+ def relay(request: RequestAPIGateway) -> dict:
22
+ return {"raw": request.raw_event.body}
23
+
24
+ lam = next(lambda_ for lambda_ in app.lambdas if lambda_.name == "relay")
25
+ response = lam.app(_make_request(api_gateway_event, "code=abc&state=x%2Fy"))
26
+
27
+ assert response.statusCode == 200
28
+
29
+
30
+ def test_invalid_json_with_body_params_still_rejected(api_gateway_event):
31
+ app = WellApi()
32
+
33
+ @app.post("/strict")
34
+ def strict(name: Annotated[str, Body(embed=True)]) -> dict:
35
+ return {"name": name}
36
+
37
+ lam = next(lambda_ for lambda_ in app.lambdas if lambda_.name == "strict")
38
+ with pytest.raises(RequestValidationError):
39
+ lam.app(_make_request(api_gateway_event, "not json"))