Skip to content

Commit c018f9c

Browse files
committed
docs: refactor routing rules syntax documentation per review feedback
- Remove redundant routing rules syntax introduction section - Update header levels from h5 to h4 for better hierarchy - Move inline code examples to separate files in examples/event_handler_rest/src - Add proper Lambda handlers with Logger and Tracer utilities - Reorganize content by moving regex pattern table to Dynamic Path Parameters section - Update tip formatting to match project style - Simplify inline comments to follow project conventions
1 parent 7bf9288 commit c018f9c

File tree

3 files changed

+79
-64
lines changed

3 files changed

+79
-64
lines changed

docs/core/event_handler/api_gateway.md

Lines changed: 12 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -214,90 +214,38 @@ Each dynamic route you set must be part of your function signature. This allows
214214
???+ tip
215215
You can also nest dynamic paths, for example `/todos/<todo_id>/<todo_status>`.
216216

217-
#### Routing Rules Syntax
217+
#### Dynamic Path Parameters
218218

219-
The routing system uses a specific syntax to define dynamic URL patterns. Understanding this syntax is crucial for creating flexible and robust API routes.
220-
221-
##### Dynamic Path Parameters
222-
223-
Dynamic path parameters are defined using angle brackets `<parameter_name>` syntax. These parameters are automatically converted to regex patterns for efficient route matching.
219+
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.
224220

225221
**Syntax**: `/path/<parameter_name>`
226222

227223
* **Parameter names** must contain only word characters (letters, numbers, underscore)
228224
* **Captured values** can contain letters, numbers, underscores, and these special characters: `-._~()'!*:@,;=+&$%<> \[]{}|^`
229225

230-
=== "routing_syntax_basic.py"
231-
232-
```python
233-
from aws_lambda_powertools.event_handler import APIGatewayRestResolver
234-
235-
app = APIGatewayRestResolver()
236-
237-
@app.get("/users/<user_id>")
238-
def get_user(user_id: str):
239-
# user_id can be: "123", "user-456", "john.doe", "user_with_underscores"
240-
return {"user_id": user_id}
241-
242-
@app.get("/orders/<order_id>/items/<item_id>")
243-
def get_order_item(order_id: str, item_id: str):
244-
# Multiple parameters: /orders/ORD-123/items/ITEM_456
245-
return {"order_id": order_id, "item_id": item_id}
246-
```
247-
248-
##### Regex Pattern Conversion
249-
250-
Behind the scenes, dynamic routes are converted to regex patterns for efficient matching:
251-
252226
| Route Pattern | Generated Regex | Matches | Doesn't Match |
253227
|---------------|-----------------|---------|---------------|
254228
| `/users/<user_id>` | `^/users/(?P<user_id>[-._~()'!*:@,;=+&$%<> \[\]{}|^\w]+)$` | `/users/123`, `/users/user-456` | `/users/123/profile` |
255229
| `/api/<version>/users` | `^/api/(?P<version>[-._~()'!*:@,;=+&$%<> \[\]{}|^\w]+)/users$` | `/api/v1/users`, `/api/2.0/users` | `/api/users` |
256230
| `/files/<path>` | `^/files/(?P<path>[-._~()'!*:@,;=+&$%<> \[\]{}|^\w]+)$` | `/files/document.pdf`, `/files/folder%20name` | `/files/sub/folder/file.txt` |
257231

258-
???+ warning "Route Matching Behavior"
259-
* Routes are matched **exactly** - no partial matches
260-
* Dynamic parameters match **non-slash characters only** by default
261-
* For paths with slashes, use [catch-all routes](#catch-all-routes) instead
232+
=== "routing_syntax_basic.py"
262233

263-
##### Advanced Examples
234+
```python hl_lines="11 18"
235+
--8<-- "examples/event_handler_rest/src/routing_syntax_basic.py"
236+
```
264237

265-
**Complex Parameter Names**
266238

267-
```python
268-
@app.get("/api/<api_version>/resources/<resource_type>/<resource_id>")
269-
def get_resource(api_version: str, resource_type: str, resource_id: str):
270-
# Matches: /api/v1/resources/users/123
271-
# api_version = "v1", resource_type = "users", resource_id = "123"
272-
return {
273-
"version": api_version,
274-
"type": resource_type,
275-
"id": resource_id
276-
}
277-
```
278239

279-
**Mixed Static and Dynamic Paths**
240+
#### Advanced Examples
280241

281-
```python
282-
@app.get("/organizations/<org_id>/teams/<team_id>/members")
283-
def list_team_members(org_id: str, team_id: str):
284-
# Matches: /organizations/acme-corp/teams/engineering/members
285-
return {"org": org_id, "team": team_id, "action": "list_members"}
286-
```
287-
288-
**Handling Special Characters**
242+
=== "routing_advanced_examples.py"
289243

290-
```python
291-
@app.get("/files/<filename>")
292-
def get_file(filename: str):
293-
# These all work:
294-
# /files/document.pdf → filename = "document.pdf"
295-
# /files/my-file_v2.txt → filename = "my-file_v2.txt"
296-
# /files/file%20with%20spaces → filename = "file%20with%20spaces"
297-
return {"filename": filename}
298-
```
244+
```python hl_lines="12 25 33"
245+
--8<-- "examples/event_handler_rest/src/routing_advanced_examples.py"
246+
```
299247

300-
???+ tip "Function Parameter Names Must Match"
248+
???+ tip "Function parameter names must match"
301249
The parameter names in your route (`<user_id>`) must exactly match the parameter names in your function signature (`user_id: str`). This is how the framework knows which captured values to pass to which parameters.
302250

303251
#### Catch-all routes
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
from aws_lambda_powertools import Logger, Tracer
2+
from aws_lambda_powertools.event_handler import APIGatewayRestResolver
3+
from aws_lambda_powertools.logging import correlation_paths
4+
from aws_lambda_powertools.utilities.typing import LambdaContext
5+
6+
tracer = Tracer()
7+
logger = Logger()
8+
app = APIGatewayRestResolver()
9+
10+
11+
@app.get("/api/<api_version>/resources/<resource_type>/<resource_id>")
12+
@tracer.capture_method
13+
def get_resource(api_version: str, resource_type: str, resource_id: str):
14+
# handles nested dynamic parameters in API versioned routes
15+
return {
16+
"version": api_version,
17+
"type": resource_type,
18+
"id": resource_id
19+
}
20+
21+
22+
@app.get("/organizations/<org_id>/teams/<team_id>/members")
23+
@tracer.capture_method
24+
def list_team_members(org_id: str, team_id: str):
25+
# combines dynamic paths with static segments
26+
return {"org": org_id, "team": team_id, "action": "list_members"}
27+
28+
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+
36+
@logger.inject_lambda_context(correlation_id_path=correlation_paths.API_GATEWAY_REST)
37+
@tracer.capture_lambda_handler
38+
def lambda_handler(event: dict, context: LambdaContext) -> dict:
39+
return app.resolve(event, context)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
from aws_lambda_powertools import Logger, Tracer
2+
from aws_lambda_powertools.event_handler import APIGatewayRestResolver
3+
from aws_lambda_powertools.logging import correlation_paths
4+
from aws_lambda_powertools.utilities.typing import LambdaContext
5+
6+
tracer = Tracer()
7+
logger = Logger()
8+
app = APIGatewayRestResolver()
9+
10+
11+
@app.get("/users/<user_id>")
12+
@tracer.capture_method
13+
def get_user(user_id: str):
14+
# user_id value comes as a string with special chars support
15+
return {"user_id": user_id}
16+
17+
18+
@app.get("/orders/<order_id>/items/<item_id>")
19+
@tracer.capture_method
20+
def get_order_item(order_id: str, item_id: str):
21+
# multiple dynamic parameters are supported
22+
return {"order_id": order_id, "item_id": item_id}
23+
24+
25+
@logger.inject_lambda_context(correlation_id_path=correlation_paths.API_GATEWAY_REST)
26+
@tracer.capture_lambda_handler
27+
def lambda_handler(event: dict, context: LambdaContext) -> dict:
28+
return app.resolve(event, context)

0 commit comments

Comments
 (0)