Skip to content

Commit 85b5ff8

Browse files
author
Michael Brewer
committed
feat(event-handler): Add PATCH decorator
1 parent 9ee7702 commit 85b5ff8

File tree

2 files changed

+55
-30
lines changed

2 files changed

+55
-30
lines changed

aws_lambda_powertools/event_handler/api_gateway.py

+16-13
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class ProxyEventType(Enum):
1616
api_gateway = http_api_v1
1717

1818

19-
class RouteEntry:
19+
class Route:
2020
def __init__(
2121
self, method: str, rule: Any, func: Callable, cors: bool, compress: bool, cache_control: Optional[str]
2222
):
@@ -34,7 +34,7 @@ class ApiGatewayResolver:
3434

3535
def __init__(self, proxy_type: Enum = ProxyEventType.http_api_v1):
3636
self._proxy_type = proxy_type
37-
self._routes: List[RouteEntry] = []
37+
self._routes: List[Route] = []
3838

3939
def get(self, rule: str, cors: bool = False, compress: bool = False, cache_control: str = None):
4040
return self.route(rule, "GET", cors, compress, cache_control)
@@ -48,14 +48,25 @@ def put(self, rule: str, cors: bool = False, compress: bool = False, cache_contr
4848
def delete(self, rule: str, cors: bool = False, compress: bool = False, cache_control: str = None):
4949
return self.route(rule, "DELETE", cors, compress, cache_control)
5050

51+
def patch(self, rule: str, cors: bool = False, compress: bool = False, cache_control: str = None):
52+
return self.route(rule, "PATCH", cors, compress, cache_control)
53+
5154
def route(self, rule: str, method: str, cors: bool = False, compress: bool = False, cache_control: str = None):
5255
def register_resolver(func: Callable):
53-
self._append(func, rule, method, cors, compress, cache_control)
56+
self._add(func, rule, method, cors, compress, cache_control)
5457
return func
5558

5659
return register_resolver
5760

58-
def resolve(self, event: Dict, context: LambdaContext) -> Dict:
61+
def _add(self, func: Callable, rule: str, method: str, cors: bool, compress: bool, cache_control: Optional[str]):
62+
self._routes.append(Route(method, self._build_rule_pattern(rule), func, cors, compress, cache_control))
63+
64+
@staticmethod
65+
def _build_rule_pattern(rule: str):
66+
rule_regex: str = re.sub(r"(<\w+>)", r"(?P\1.+)", rule)
67+
return re.compile("^{}$".format(rule_regex))
68+
69+
def resolve(self, event, context) -> Dict[str, Any]:
5970
self.current_event = self._as_data_class(event)
6071
self.lambda_context = context
6172

@@ -88,22 +99,14 @@ def resolve(self, event: Dict, context: LambdaContext) -> Dict:
8899

89100
return {"statusCode": status_code, "headers": headers, "body": body, "isBase64Encoded": base64_encoded}
90101

91-
def _append(self, func: Callable, rule: str, method: str, cors: bool, compress: bool, cache_control: Optional[str]):
92-
self._routes.append(RouteEntry(method, self._build_rule_pattern(rule), func, cors, compress, cache_control))
93-
94-
@staticmethod
95-
def _build_rule_pattern(rule: str):
96-
rule_regex: str = re.sub(r"(<\w+>)", r"(?P\1.+)", rule)
97-
return re.compile("^{}$".format(rule_regex))
98-
99102
def _as_data_class(self, event: Dict) -> BaseProxyEvent:
100103
if self._proxy_type == ProxyEventType.http_api_v1:
101104
return APIGatewayProxyEvent(event)
102105
if self._proxy_type == ProxyEventType.http_api_v2:
103106
return APIGatewayProxyEventV2(event)
104107
return ALBEvent(event)
105108

106-
def _find_route(self, method: str, path: str) -> Tuple[RouteEntry, Dict]:
109+
def _find_route(self, method: str, path: str) -> Tuple[Route, Dict]:
107110
method = method.upper()
108111
for route in self._routes:
109112
if method != route.method:

tests/functional/event_handler/test_api_gateway.py

+39-17
Original file line numberDiff line numberDiff line change
@@ -50,21 +50,6 @@ def get_lambda():
5050
assert result["headers"]["Content-Type"] == "application/json"
5151

5252

53-
def test_include_rule_matching():
54-
app = ApiGatewayResolver()
55-
56-
@app.get("/<name>/<my_id>")
57-
def get_lambda(my_id: str, name: str):
58-
assert name == "my"
59-
return 200, "plain/html", my_id
60-
61-
result = app(load_event("apiGatewayProxyEvent.json"), {})
62-
63-
assert result["statusCode"] == 200
64-
assert result["headers"]["Content-Type"] == "plain/html"
65-
assert result["body"] == "path"
66-
67-
6853
def test_api_gateway():
6954
app = ApiGatewayResolver(proxy_type=ProxyEventType.api_gateway)
7055

@@ -96,24 +81,61 @@ def my_path():
9681
assert result["body"] == "tom"
9782

9883

84+
def test_include_rule_matching():
85+
app = ApiGatewayResolver()
86+
87+
@app.get("/<name>/<my_id>")
88+
def get_lambda(my_id: str, name: str):
89+
assert name == "my"
90+
return 200, "plain/html", my_id
91+
92+
result = app(load_event("apiGatewayProxyEvent.json"), {})
93+
94+
assert result["statusCode"] == 200
95+
assert result["headers"]["Content-Type"] == "plain/html"
96+
assert result["body"] == "path"
97+
98+
9999
def test_no_matches():
100100
app = ApiGatewayResolver()
101101

102102
@app.get("/not_matching_get")
103103
def no_get_matching():
104104
raise RuntimeError()
105105

106-
@app.put("/no_matching")
106+
@app.post("/no_matching_post")
107+
def no_post_matching():
108+
raise RuntimeError()
109+
110+
@app.put("/no_matching_put")
107111
def no_put_matching():
108112
raise RuntimeError()
109113

110-
@app.delete("/no_matching")
114+
@app.delete("/no_matching_delete")
111115
def no_delete_matching():
112116
raise RuntimeError()
113117

118+
@app.patch("/no_matching_patch")
119+
def no_patch_matching():
120+
raise RuntimeError()
121+
114122
def handler(event, context):
115123
app.resolve(event, context)
116124

125+
routes = app._routes
126+
assert len(routes) == 5
127+
for route in routes:
128+
if route.func == no_get_matching:
129+
assert route.method == "GET"
130+
if route.func == no_post_matching:
131+
assert route.method == "POST"
132+
if route.func == no_put_matching:
133+
assert route.method == "PUT"
134+
if route.func == no_delete_matching:
135+
assert route.method == "DELETE"
136+
if route.func == no_patch_matching:
137+
assert route.method == "PATCH"
138+
117139
with pytest.raises(ValueError):
118140
handler(load_event("apiGatewayProxyEvent.json"), None)
119141

0 commit comments

Comments
 (0)