Skip to content

Commit 5974441

Browse files
Small changes
1 parent c018f9c commit 5974441

File tree

4 files changed

+49
-73
lines changed

4 files changed

+49
-73
lines changed

docs/core/event_handler/api_gateway.md

Lines changed: 20 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,8 @@ You can use `/todos/<todo_id>` to configure dynamic URL paths, where `<todo_id>`
196196

197197
Each dynamic route you set must be part of your function signature. This allows us to call your function using keyword arguments when matching your dynamic route.
198198

199-
???+ note
200-
For brevity, we will only include the necessary keys for each sample request for the example to work.
199+
???+ tip
200+
You can also nest dynamic paths, for example `/todos/<todo_id>/<todo_status>`.
201201

202202
=== "dynamic_routes.py"
203203

@@ -211,37 +211,31 @@ Each dynamic route you set must be part of your function signature. This allows
211211
--8<-- "examples/event_handler_rest/src/dynamic_routes.json"
212212
```
213213

214-
???+ tip
215-
You can also nest dynamic paths, for example `/todos/<todo_id>/<todo_status>`.
216-
217-
#### Dynamic Path Parameters
214+
#### Dynamic path mechanism
218215

219216
Dynamic path parameters are defined using angle brackets `<parameter_name>` syntax. These parameters are automatically converted to regex patterns for efficient route matching and performance gains.
220217

221218
**Syntax**: `/path/<parameter_name>`
222219

223220
* **Parameter names** must contain only word characters (letters, numbers, underscore)
224-
* **Captured values** can contain letters, numbers, underscores, and these special characters: `-._~()'!*:@,;=+&$%<> \[]{}|^`
221+
* **Captured values** can contain letters, numbers, underscores, and these special characters: `-._~()'!*:@,;=+&$%<> \[]{}|^`. Reserved characters must be percent-encoded in URLs to prevent errors.
225222

226-
| Route Pattern | Generated Regex | Matches | Doesn't Match |
227-
|---------------|-----------------|---------|---------------|
228-
| `/users/<user_id>` | `^/users/(?P<user_id>[-._~()'!*:@,;=+&$%<> \[\]{}|^\w]+)$` | `/users/123`, `/users/user-456` | `/users/123/profile` |
229-
| `/api/<version>/users` | `^/api/(?P<version>[-._~()'!*:@,;=+&$%<> \[\]{}|^\w]+)/users$` | `/api/v1/users`, `/api/2.0/users` | `/api/users` |
230-
| `/files/<path>` | `^/files/(?P<path>[-._~()'!*:@,;=+&$%<> \[\]{}|^\w]+)$` | `/files/document.pdf`, `/files/folder%20name` | `/files/sub/folder/file.txt` |
223+
| Route Pattern | Matches | Doesn't Match |
224+
|---------------|---------|---------------|
225+
| `/users/<user_id>` | `/users/123`, `/users/user-456` | `/users/123/profile` |
226+
| `/api/<version>/users` | `/api/v1/users`, `/api/2.0/users` | `/api/users` |
227+
| `/files/<path>` | `/files/document.pdf`, `/files/folder%20name` | `/files/sub/folder/file.txt` |
228+
| `/files/<folder>/<name>` | `/files/src/document.pdf`, `/files/src/test.txt` | `/files/sub/folder/file.txt` |
231229

232230
=== "routing_syntax_basic.py"
233231

234232
```python hl_lines="11 18"
235233
--8<-- "examples/event_handler_rest/src/routing_syntax_basic.py"
236234
```
237235

238-
239-
240-
#### Advanced Examples
241-
242236
=== "routing_advanced_examples.py"
243237

244-
```python hl_lines="12 25 33"
238+
```python hl_lines="11 22"
245239
--8<-- "examples/event_handler_rest/src/routing_advanced_examples.py"
246240
```
247241

@@ -250,14 +244,13 @@ Dynamic path parameters are defined using angle brackets `<parameter_name>` synt
250244

251245
#### Catch-all routes
252246

253-
???+ note
254-
We recommend having explicit routes whenever possible; use catch-all routes sparingly.
255-
256247
For scenarios where you need to handle arbitrary or deeply nested paths, you can use regex patterns directly in your route definitions. These are particularly useful for proxy routes or when dealing with file paths.
257248

249+
**We recommend** having explicit routes whenever possible; use catch-all routes sparingly.
250+
258251
##### Using Regex Patterns
259252

260-
You can use standard [Python regex patterns](https://docs.python.org/3/library/re.html#regular-expression-syntax){target="_blank" rel="nofollow"} in your route definitions:
253+
You can use standard [Python regex patterns](https://docs.python.org/3/library/re.html#regular-expression-syntax){target="_blank" rel="nofollow"} in your route definitions, for example:
261254

262255
| Pattern | Description | Examples |
263256
|---------|-------------|----------|
@@ -266,53 +259,17 @@ You can use standard [Python regex patterns](https://docs.python.org/3/library/r
266259
| `[^/]+` | Matches one or more non-slash characters | `/api/[^/]+` matches `/api/v1` but not `/api/v1/users` |
267260
| `\w+` | Matches one or more word characters | `/users/\w+` matches `/users/john123` |
268261

269-
**Common Regex Route Examples:**
270-
271-
```python
272-
# File path proxy - captures everything after /files/
273-
@app.get("/files/.+")
274-
def serve_file():
275-
file_path = app.current_event.path.replace("/files/", "")
276-
return {"file_path": file_path}
277-
278-
# API versioning with any format
279-
@app.get("/api/v\d+/.*") # Matches /api/v1/users, /api/v2/posts/123
280-
def handle_versioned_api():
281-
return {"api_version": "handled"}
282-
283-
# Catch-all for unmatched routes
284-
@app.route(".*", method=["GET", "POST"]) # Must be last route
285-
def catch_all():
286-
return {"message": "Route not found", "path": app.current_event.path}
287-
```
288-
289-
##### Combining Dynamic Parameters with Regex
290-
291-
```python
292-
# Mixed: dynamic parameter + regex catch-all
293-
@app.get("/users/<user_id>/files/.+")
294-
def get_user_files(user_id: str):
295-
file_path = app.current_event.path.split(f"/users/{user_id}/files/")[1]
296-
return {"user_id": user_id, "file_path": file_path}
297-
```
298-
299-
???+ warning "Route Matching Priority"
300-
* Routes are matched in **order of specificity**, not registration order
301-
* More specific routes (exact matches) take precedence over regex patterns
302-
* Among regex routes, the first registered matching route wins
303-
* Always place catch-all routes (`.*`) last
304-
305262
=== "dynamic_routes_catch_all.py"
306263

307-
```python hl_lines="11"
264+
```python hl_lines="11 17 18 24 25 30 31 36 37"
308265
--8<-- "examples/event_handler_rest/src/dynamic_routes_catch_all.py"
309266
```
310267

311-
=== "dynamic_routes_catch_all.json"
312-
313-
```json
314-
--8<-- "examples/event_handler_rest/src/dynamic_routes_catch_all.json"
315-
```
268+
???+ warning "Route Matching Priority"
269+
- Routes are matched in **order of specificity**, not registration order
270+
- More specific routes (exact matches) take precedence over regex patterns
271+
- Among regex routes, the first registered matching route wins
272+
- Always place catch-all routes (`.*`) last
316273

317274
### HTTP Methods
318275

examples/event_handler_rest/src/dynamic_routes_catch_all.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,32 @@ def catch_any_route_get_method():
1414
return {"path_received": app.current_event.path}
1515

1616

17+
# File path proxy - captures everything after /files/
18+
@app.get("/files/.+")
19+
def serve_file():
20+
file_path = app.current_event.path.replace("/files/", "")
21+
return {"file_path": file_path}
22+
23+
24+
# API versioning with any format
25+
@app.get(r"/api/v\d+/.*") # Matches /api/v1/users, /api/v2/posts/123
26+
def handle_versioned_api():
27+
return {"api_version": "handled"}
28+
29+
30+
# Catch-all for unmatched routes
31+
@app.route(".*", method=["GET", "POST"]) # Must be last route
32+
def catch_all():
33+
return {"message": "Route not found", "path": app.current_event.path}
34+
35+
36+
# Mixed: dynamic parameter + regex catch-all
37+
@app.get("/users/<user_id>/files/.+")
38+
def get_user_files(user_id: str):
39+
file_path = app.current_event.path.split(f"/users/{user_id}/files/")[1]
40+
return {"user_id": user_id, "file_path": file_path}
41+
42+
1743
# You can continue to use other utilities just as before
1844
@logger.inject_lambda_context(correlation_id_path=correlation_paths.API_GATEWAY_REST)
1945
@tracer.capture_lambda_handler

examples/event_handler_rest/src/routing_advanced_examples.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def get_resource(api_version: str, resource_type: str, resource_id: str):
1515
return {
1616
"version": api_version,
1717
"type": resource_type,
18-
"id": resource_id
18+
"id": resource_id,
1919
}
2020

2121

@@ -26,14 +26,7 @@ def list_team_members(org_id: str, team_id: str):
2626
return {"org": org_id, "team": team_id, "action": "list_members"}
2727

2828

29-
@app.get("/files/<filename>")
30-
@tracer.capture_method
31-
def get_file(filename: str):
32-
# handles special characters including dots, dashes, and URL-encoded spaces
33-
return {"filename": filename}
34-
35-
3629
@logger.inject_lambda_context(correlation_id_path=correlation_paths.API_GATEWAY_REST)
3730
@tracer.capture_lambda_handler
3831
def lambda_handler(event: dict, context: LambdaContext) -> dict:
39-
return app.resolve(event, context)
32+
return app.resolve(event, context)

examples/event_handler_rest/src/routing_syntax_basic.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,4 @@ def get_order_item(order_id: str, item_id: str):
2525
@logger.inject_lambda_context(correlation_id_path=correlation_paths.API_GATEWAY_REST)
2626
@tracer.capture_lambda_handler
2727
def lambda_handler(event: dict, context: LambdaContext) -> dict:
28-
return app.resolve(event, context)
28+
return app.resolve(event, context)

0 commit comments

Comments
 (0)