0
# Templated Links
1
2
Support for HAL templated links with parameter expansion and URI template processing. RestNavigator handles RFC 6570 URI templates transparently, allowing dynamic URL construction from templates.
3
4
## Capabilities
5
6
### Template Navigation
7
8
Navigate templated links by providing required parameters to expand URLs dynamically.
9
10
```python { .api }
11
class PartialNavigator:
12
def __call__(self, **kwargs) -> 'HALNavigator':
13
"""
14
Expand template parameters to create a full HALNavigator.
15
16
Parameters:
17
- **kwargs: Template variable values
18
19
Returns:
20
HALNavigator for the expanded URI
21
"""
22
23
def expand_uri(self, **kwargs) -> str:
24
"""
25
Expand template to URI string without creating navigator.
26
27
Parameters:
28
- **kwargs: Template variable values
29
30
Returns:
31
Expanded URI string
32
"""
33
34
def expand_link(self, **kwargs) -> 'Link':
35
"""
36
Expand template to Link object.
37
38
Parameters:
39
- **kwargs: Template variable values
40
41
Returns:
42
Link object with expanded URI
43
"""
44
45
@property
46
def variables(self) -> set:
47
"""
48
Set of template variable names required for expansion.
49
50
Returns:
51
Set of variable names
52
"""
53
54
@property
55
def template_uri(self) -> str:
56
"""
57
The templated URI string before expansion.
58
59
Returns:
60
Original template URI
61
"""
62
```
63
64
### Template Discovery and Usage
65
66
```python
67
# Discover templated links
68
api_links = api.links()
69
user_template = api_links['ht:user'] # Returns PartialNavigator
70
71
# Check if it's a template
72
if hasattr(user_template, 'variables'):
73
print("Template variables:", user_template.variables)
74
print("Template URI:", user_template.template_uri)
75
76
# Expand template with parameters
77
user = user_template(name='john_doe')
78
79
# Alternative expansion methods
80
user_uri = user_template.expand_uri(name='john_doe')
81
user_link = user_template.expand_link(name='john_doe')
82
```
83
84
### Complex Template Examples
85
86
```python
87
# Single parameter template
88
# Template: "/users/{id}"
89
user = api['users'](id=123)
90
91
# Multiple parameter template
92
# Template: "/users/{id}/posts{?page,limit}"
93
posts = api['users'](id=123)['posts'](page=2, limit=10)
94
95
# Optional parameters (query strings)
96
# Template: "/search{?q,type,sort}"
97
search_results = api['search'](q='python', type='repositories')
98
99
# Complex template with path and query parameters
100
# Template: "/repos/{owner}/{repo}/issues{?state,labels,sort}"
101
issues = api['repos'](owner='octocat', repo='Hello-World')['issues'](
102
state='open',
103
labels='bug,enhancement',
104
sort='created'
105
)
106
```
107
108
### Template Validation and Error Handling
109
110
```python
111
# Check required variables before expansion
112
search_template = api['search']
113
required_vars = search_template.variables
114
print(f"Required parameters: {required_vars}")
115
116
# Partial expansion (providing only some parameters)
117
try:
118
# This might fail if 'q' is required
119
incomplete = api['search'](type='users') # Missing 'q' parameter
120
except Exception as e:
121
print("Template expansion error:", e)
122
123
# Safe expansion with validation
124
def safe_template_expand(template, **kwargs):
125
required = template.variables
126
provided = set(kwargs.keys())
127
missing = required - provided
128
129
if missing:
130
raise ValueError(f"Missing required parameters: {missing}")
131
132
return template(**kwargs)
133
134
# Usage
135
user = safe_template_expand(api['users'], id=123)
136
```
137
138
### Working with Template URIs
139
140
```python
141
# Get the raw template URI
142
template = api['users']
143
print("Template:", template.template_uri) # "/users/{id}"
144
145
# Expand to URI without creating navigator
146
user_uri = template.expand_uri(id=123) # "/users/123"
147
148
# Build full URL
149
full_url = api.session.base_url + user_uri
150
151
# Create Link object
152
link = template.expand_link(id=123)
153
print("Link URI:", link.uri)
154
print("Link properties:", link.props)
155
```
156
157
### Template Chaining
158
159
```python
160
# Chain templated navigations
161
user_posts = api['users'](id=123)['posts'](page=1)
162
163
# Equivalent to
164
user = api['users'](id=123)
165
posts = user['posts'](page=1)
166
167
# Mixed template and regular navigation
168
# api['users'](id=123)['posts', 'comments', 0]
169
specific_comment = api['users'](id=123)['posts']['comments'][0]
170
```
171
172
### Advanced Template Patterns
173
174
```python
175
# Store template for reuse
176
user_template = api['users']
177
178
# Create multiple users from same template
179
users = []
180
for user_id in [1, 2, 3, 4, 5]:
181
user = user_template(id=user_id)
182
users.append(user)
183
184
# Template with default values simulation
185
def get_user_posts(user_id, page=1, limit=20):
186
return api['users'](id=user_id)['posts'](page=page, limit=limit)
187
188
# Dynamic template parameter building
189
search_params = {'q': 'python'}
190
if include_forks:
191
search_params['fork'] = 'true'
192
if language:
193
search_params['language'] = language
194
195
results = api['search'](**search_params)
196
```
197
198
### Template Inspection
199
200
```python
201
# Inspect all templated links in a resource
202
def find_templates(navigator):
203
templates = {}
204
for rel, link in navigator.links().items():
205
if hasattr(link, 'variables'):
206
templates[rel] = {
207
'uri': link.template_uri,
208
'variables': link.variables
209
}
210
return templates
211
212
# Usage
213
api_templates = find_templates(api)
214
for rel, info in api_templates.items():
215
print(f"{rel}: {info['uri']} (vars: {info['variables']})")
216
```