Skip to content

Commit 3ffb5de

Browse files
author
Michael Brewer
committed
doc(event-handler): Add remaining docstring for the api gateway handler
1 parent 795100f commit 3ffb5de

File tree

1 file changed

+76
-9
lines changed

1 file changed

+76
-9
lines changed

aws_lambda_powertools/event_handler/api_gateway.py

+76-9
Original file line numberDiff line numberDiff line change
@@ -204,31 +204,75 @@ def build(self, event: BaseProxyEvent, cors: CORSConfig = None) -> Dict[str, Any
204204

205205

206206
class ApiGatewayResolver:
207+
"""API Gateway and ALB proxy resolver
208+
209+
Examples
210+
--------
211+
Simple example with a custom lambda handler using the Tracer capture_lambda_handler decorator
212+
213+
>>> from aws_lambda_powertools import Tracer
214+
>>> from aws_lambda_powertools.event_handler.api_gateway import (
215+
>>> ApiGatewayResolver
216+
>>> )
217+
>>>
218+
>>> tracer = Tracer()
219+
>>> app = ApiGatewayResolver()
220+
>>>
221+
>>> @app.get("/get-call")
222+
>>> def simple_get():
223+
>>> return {"message": "Foo"}
224+
>>>
225+
>>> @app.post("/post-call")
226+
>>> def simple_post():
227+
>>> post_data: dict = app.current_event.json_body
228+
>>> return {"message": post_data["value"]}
229+
>>>
230+
>>> @tracer.capture_lambda_handler
231+
>>> def lambda_handler(event, context):
232+
>>> return app.resolve(event, context)
233+
234+
"""
235+
207236
current_event: BaseProxyEvent
208237
lambda_context: LambdaContext
209238

210239
def __init__(self, proxy_type: Enum = ProxyEventType.http_api_v1, cors: CORSConfig = None):
240+
"""
241+
Parameters
242+
----------
243+
proxy_type: ProxyEventType
244+
Proxy request type, defaults to API Gateway V1
245+
cors: CORSConfig
246+
Optionally configure and enabled CORS. Not each route will need to have to cors=True
247+
"""
211248
self._proxy_type = proxy_type
212249
self._routes: List[Route] = []
213250
self._cors = cors
214251
self._cors_methods: Set[str] = {"OPTIONS"}
215252

216253
def get(self, rule: str, cors: bool = False, compress: bool = False, cache_control: str = None):
254+
"""Get route decorator with GET `method`"""
217255
return self.route(rule, "GET", cors, compress, cache_control)
218256

219257
def post(self, rule: str, cors: bool = False, compress: bool = False, cache_control: str = None):
258+
"""Post route decorator with POST `method`"""
220259
return self.route(rule, "POST", cors, compress, cache_control)
221260

222261
def put(self, rule: str, cors: bool = False, compress: bool = False, cache_control: str = None):
262+
"""Put route decorator with PUT `method`"""
223263
return self.route(rule, "PUT", cors, compress, cache_control)
224264

225265
def delete(self, rule: str, cors: bool = False, compress: bool = False, cache_control: str = None):
266+
"""Delete route decorator with DELETE `method`"""
226267
return self.route(rule, "DELETE", cors, compress, cache_control)
227268

228269
def patch(self, rule: str, cors: bool = False, compress: bool = False, cache_control: str = None):
270+
"""Patch route decorator with PATCH `method`"""
229271
return self.route(rule, "PATCH", cors, compress, cache_control)
230272

231273
def route(self, rule: str, method: str, cors: bool = False, compress: bool = False, cache_control: str = None):
274+
"""Route decorator includes parameter `method`"""
275+
232276
def register_resolver(func: Callable):
233277
self._routes.append(Route(method, self._compile_regex(rule), func, cors, compress, cache_control))
234278
if cors:
@@ -238,9 +282,22 @@ def register_resolver(func: Callable):
238282
return register_resolver
239283

240284
def resolve(self, event, context) -> Dict[str, Any]:
241-
self.current_event = self._to_data_class(event)
285+
"""Resolves the response based on the provide event and decorator routes
286+
287+
Parameters
288+
----------
289+
event: Dict[str, Any]
290+
Event
291+
context: LambdaContext
292+
Lambda context
293+
Returns
294+
-------
295+
dict
296+
Returns the dict response
297+
"""
298+
self.current_event = self._to_proxy_event(event)
242299
self.lambda_context = context
243-
return self._resolve_response().build(self.current_event, self._cors)
300+
return self._resolve().build(self.current_event, self._cors)
244301

245302
def __call__(self, event, context) -> Any:
246303
return self.resolve(event, context)
@@ -251,16 +308,16 @@ def _compile_regex(rule: str):
251308
rule_regex: str = re.sub(r"(<\w+>)", r"(?P\1.+)", rule)
252309
return re.compile("^{}$".format(rule_regex))
253310

254-
def _to_data_class(self, event: Dict) -> BaseProxyEvent:
311+
def _to_proxy_event(self, event: Dict) -> BaseProxyEvent:
255312
"""Convert the event dict to the corresponding data class"""
256313
if self._proxy_type == ProxyEventType.http_api_v1:
257314
return APIGatewayProxyEvent(event)
258315
if self._proxy_type == ProxyEventType.http_api_v2:
259316
return APIGatewayProxyEventV2(event)
260317
return ALBEvent(event)
261318

262-
def _resolve_response(self) -> ResponseBuilder:
263-
"""Resolve the response or return the not found response"""
319+
def _resolve(self) -> ResponseBuilder:
320+
"""Resolves the response or return the not found response"""
264321
method = self.current_event.http_method.upper()
265322
path = self.current_event.path
266323
for route in self._routes:
@@ -273,19 +330,21 @@ def _resolve_response(self) -> ResponseBuilder:
273330
return self._not_found(method, path)
274331

275332
def _not_found(self, method: str, path: str) -> ResponseBuilder:
276-
"""No matching route was found, includes support for the cors preflight response"""
333+
"""Called when no matching route was found and includes support for the cors preflight response"""
277334
headers = {}
278335
if self._cors:
279336
headers.update(self._cors.to_dict())
337+
280338
if method == "OPTIONS": # Preflight
281339
headers["Access-Control-Allow-Methods"] = ",".join(sorted(self._cors_methods))
282-
return ResponseBuilder(Response(status_code=204, content_type=None, body=None, headers=headers))
340+
return ResponseBuilder(Response(status_code=204, content_type=None, headers=headers, body=None))
341+
283342
return ResponseBuilder(
284343
Response(
285344
status_code=404,
286345
content_type="application/json",
287-
body=json.dumps({"message": f"No route found for '{method}.{path}'"}),
288346
headers=headers,
347+
body=json.dumps({"message": f"No route found for '{method}.{path}'"}),
289348
)
290349
)
291350

@@ -295,7 +354,15 @@ def _call_route(self, route: Route, args: Dict[str, str]) -> ResponseBuilder:
295354

296355
@staticmethod
297356
def _to_response(result: Union[Tuple[int, str, Union[bytes, str]], Dict, Response]) -> Response:
298-
"""Convert the route result to a Response"""
357+
"""Convert the route's result to a Response
358+
359+
3 main result types are supported:
360+
361+
- Tuple[int, str, bytes] and Tuple[int, str, str]: status code, content-type and body (str|bytes)
362+
- Dict[str, Any]: Rest api response with just the Dict to json stringify and content-type is set to
363+
application/json
364+
- Response: returned as is, and allows for more flexibility
365+
"""
299366
if isinstance(result, Response):
300367
return result
301368
elif isinstance(result, dict):

0 commit comments

Comments
 (0)