|
1 | 1 | from __future__ import annotations |
2 | 2 |
|
3 | 3 | import base64 |
4 | | -import inspect |
5 | 4 | import warnings |
6 | 5 | from typing import TYPE_CHECKING, Any, Callable |
7 | 6 | from urllib.parse import parse_qs |
|
10 | 9 | ApiGatewayResolver, |
11 | 10 | BaseRouter, |
12 | 11 | ProxyEventType, |
13 | | - Response, |
14 | | - Route, |
15 | 12 | ) |
16 | | -from aws_lambda_powertools.event_handler.middlewares.async_utils import wrap_middleware_async |
17 | 13 | from aws_lambda_powertools.shared.headers_serializer import BaseHeadersSerializer |
18 | 14 | from aws_lambda_powertools.utilities.data_classes.common import BaseProxyEvent |
19 | 15 |
|
@@ -240,113 +236,13 @@ def _get_base_path(self) -> str: |
240 | 236 | return "" |
241 | 237 |
|
242 | 238 | async def _resolve_async(self) -> dict: # type: ignore[override] |
243 | | - """Async version of resolve that supports async handlers.""" |
244 | | - method = self.current_event.http_method.upper() |
245 | | - path = self._remove_prefix(self.current_event.path) |
246 | | - |
247 | | - registered_routes = self._static_routes + self._dynamic_routes |
248 | | - |
249 | | - for route in registered_routes: |
250 | | - if method != route.method: |
251 | | - continue |
252 | | - match_results = route.rule.match(path) |
253 | | - if match_results: |
254 | | - self.append_context(_route=route, _path=path) |
255 | | - route_keys = self._convert_matches_into_route_keys(match_results) |
256 | | - return await self._call_route_async(route, route_keys) |
257 | | - |
258 | | - # Handle not found |
259 | | - return await self._handle_not_found_async() |
260 | | - |
261 | | - async def _call_route_async(self, route: Route, route_arguments: dict[str, str]) -> dict: # type: ignore[override] |
262 | | - """Call route handler, supporting both sync and async handlers.""" |
263 | | - from aws_lambda_powertools.event_handler.api_gateway import ResponseBuilder |
264 | | - |
265 | | - try: |
266 | | - self._reset_processed_stack() |
267 | | - |
268 | | - # Get the route args (may be modified by validation middleware) |
269 | | - self.append_context(_route_args=route_arguments) |
270 | | - |
271 | | - # Run middleware chain (sync for now, handlers can be async) |
272 | | - response = await self._run_middleware_chain_async(route) |
273 | | - |
274 | | - response_builder: ResponseBuilder = ResponseBuilder( |
275 | | - response=response, |
276 | | - serializer=self._serializer, |
277 | | - route=route, |
278 | | - ) |
279 | | - |
280 | | - return response_builder.build(self.current_event, self._cors) |
281 | | - |
282 | | - except Exception as exc: |
283 | | - exc_response_builder = self._call_exception_handler(exc, route) |
284 | | - if exc_response_builder: |
285 | | - return exc_response_builder.build(self.current_event, self._cors) |
286 | | - raise |
287 | | - |
288 | | - async def _run_middleware_chain_async(self, route: Route) -> Response: |
289 | | - """Run the middleware chain, awaiting async handlers.""" |
290 | | - # Build middleware list |
291 | | - all_middlewares: list[Callable[..., Any]] = [] |
292 | | - |
293 | | - # Determine if validation should be enabled for this route |
294 | | - # If route has explicit enable_validation setting, use it; otherwise, use resolver's global setting |
295 | | - route_validation_enabled = ( |
296 | | - route.enable_validation if route.enable_validation is not None else self._enable_validation |
297 | | - ) |
298 | | - |
299 | | - if route_validation_enabled and hasattr(self, "_request_validation_middleware"): |
300 | | - all_middlewares.append(self._request_validation_middleware) |
301 | | - |
302 | | - all_middlewares.extend(self._router_middlewares + route.middlewares) |
303 | | - |
304 | | - if route_validation_enabled and hasattr(self, "_response_validation_middleware"): |
305 | | - all_middlewares.append(self._response_validation_middleware) |
306 | | - |
307 | | - # Create the final handler that calls the route function |
308 | | - async def final_handler(app): |
309 | | - route_args = app.context.get("_route_args", {}) |
310 | | - result = route.func(**route_args) |
311 | | - |
312 | | - # Await if coroutine |
313 | | - if inspect.iscoroutine(result): |
314 | | - result = await result |
315 | | - |
316 | | - return self._to_response(result) |
317 | | - |
318 | | - # Build middleware chain from end to start |
319 | | - next_handler = final_handler |
320 | | - |
321 | | - for middleware in reversed(all_middlewares): |
322 | | - next_handler = wrap_middleware_async(middleware, next_handler) |
323 | | - |
324 | | - return await next_handler(self) |
325 | | - |
326 | | - async def _handle_not_found_async(self, method: str = "", path: str = "") -> dict: # type: ignore[override] |
327 | | - """Handle 404 responses, using custom not_found handler if registered.""" |
328 | | - from http import HTTPStatus |
329 | | - |
330 | | - from aws_lambda_powertools.event_handler.api_gateway import ResponseBuilder |
331 | | - from aws_lambda_powertools.event_handler.exceptions import NotFoundError |
332 | | - |
333 | | - # Check for custom not_found handler |
334 | | - custom_not_found_handler = self.exception_handler_manager.lookup_exception_handler(NotFoundError) |
335 | | - if custom_not_found_handler: |
336 | | - response = custom_not_found_handler(NotFoundError()) |
337 | | - else: |
338 | | - response = Response( |
339 | | - status_code=HTTPStatus.NOT_FOUND.value, |
340 | | - content_type="application/json", |
341 | | - body={"statusCode": HTTPStatus.NOT_FOUND.value, "message": "Not found"}, |
342 | | - ) |
343 | | - |
344 | | - response_builder: ResponseBuilder = ResponseBuilder( |
345 | | - response=response, |
346 | | - serializer=self._serializer, |
347 | | - route=None, |
348 | | - ) |
| 239 | + """Thin async resolver: delegates entirely to the parent and serializes to dict. |
349 | 240 |
|
| 241 | + The parent's _resolve_async handles route matching, CORS preflight, not-found |
| 242 | + logic, and exception handling. The only adaptation needed here is converting |
| 243 | + the returned ResponseBuilder into the dict format that asgi_handler expects. |
| 244 | + """ |
| 245 | + response_builder = await super()._resolve_async() |
350 | 246 | return response_builder.build(self.current_event, self._cors) |
351 | 247 |
|
352 | 248 | async def asgi_handler(self, scope: dict, receive: Callable, send: Callable) -> None: |
|
0 commit comments