0
# Spec Loading
1
2
Utilities for loading OpenAPI/Swagger specifications from URLs, local files, and YAML/JSON sources with support for remote references and custom headers. The spec loading system provides flexible ways to load specifications while handling various formats and sources.
3
4
## Capabilities
5
6
### Loader
7
8
Primary abstraction for loading Swagger/OpenAPI specifications from various sources. Handles both JSON and YAML formats, remote references, and custom request headers.
9
10
```python { .api }
11
class Loader:
12
def __init__(self, http_client, request_headers: dict = None): ...
13
def load_spec(self, spec_url: str, base_url: str = None) -> dict: ...
14
def load_yaml(self, text: str) -> dict: ...
15
```
16
17
**Parameters:**
18
- `http_client`: HTTP client instance for fetching remote specs
19
- `request_headers` (dict): Headers to include with HTTP requests when loading specs
20
- `spec_url` (str): URL or file path to the OpenAPI specification
21
- `base_url` (str): Base URL for resolving relative references in the spec
22
- `text` (str): YAML text content to parse
23
24
**Returns:**
25
- `load_spec`: Parsed specification as a dictionary
26
- `load_yaml`: Parsed YAML content as a dictionary
27
28
**Usage Example:**
29
30
```python
31
from bravado.swagger_model import Loader
32
from bravado.requests_client import RequestsClient
33
34
# Create loader with HTTP client
35
http_client = RequestsClient()
36
loader = Loader(http_client)
37
38
# Load from URL
39
spec_dict = loader.load_spec('https://petstore.swagger.io/v2/swagger.json')
40
41
# Load with custom headers
42
loader_with_auth = Loader(
43
http_client,
44
request_headers={'Authorization': 'Bearer token123'}
45
)
46
spec_dict = loader_with_auth.load_spec('https://api.example.com/swagger.yaml')
47
48
# Load YAML from string
49
yaml_content = """
50
openapi: 3.0.0
51
info:
52
title: Test API
53
version: 1.0.0
54
paths: {}
55
"""
56
spec_dict = loader.load_yaml(yaml_content)
57
```
58
59
### FileEventual
60
61
Adapter for loading local files with an EventualResult-like interface, supporting both synchronous and asynchronous-style access to local specification files.
62
63
```python { .api }
64
class FileEventual:
65
def __init__(self, path: str): ...
66
def get_path(self) -> str: ...
67
def wait(self, **kwargs): ...
68
def result(self, *args, **kwargs): ...
69
def cancel(self): ...
70
```
71
72
**Nested Classes:**
73
74
```python { .api }
75
class FileEventual.FileResponse:
76
def __init__(self, data: bytes): ...
77
def json(self): ...
78
```
79
80
**Parameters:**
81
- `path` (str): Path to the specification file
82
- `data` (bytes): File content data
83
84
**Methods:**
85
- `get_path()`: Get file path with .json extension added if needed
86
- `wait()`: Load and return file contents
87
- `result()`: Alias for wait() method
88
- `cancel()`: No-op cancel method for interface compatibility
89
90
**Usage Example:**
91
92
```python
93
from bravado.swagger_model import FileEventual
94
95
# Load local file
96
file_eventual = FileEventual('/path/to/swagger.json')
97
file_response = file_eventual.wait()
98
spec_dict = file_response.json()
99
100
# Automatic .json extension handling
101
file_eventual = FileEventual('/path/to/swagger') # Will try /path/to/swagger.json
102
file_response = file_eventual.wait()
103
```
104
105
### Utility Functions
106
107
Helper functions for loading specifications from various sources.
108
109
#### load_file
110
111
Load OpenAPI specification from a local file.
112
113
```python { .api }
114
def load_file(spec_file: str, http_client=None) -> dict: ...
115
```
116
117
**Parameters:**
118
- `spec_file` (str): Path to the specification file
119
- `http_client`: HTTP client instance (optional, defaults to RequestsClient)
120
121
**Returns:**
122
- Parsed specification dictionary
123
124
#### load_url
125
126
Load OpenAPI specification from a URL.
127
128
```python { .api }
129
def load_url(spec_url: str, http_client=None, base_url: str = None) -> dict: ...
130
```
131
132
**Parameters:**
133
- `spec_url` (str): URL to the specification
134
- `http_client`: HTTP client instance (optional, defaults to RequestsClient)
135
- `base_url` (str): Base URL for resolving relative references
136
137
**Returns:**
138
- Parsed specification dictionary
139
140
#### request
141
142
Low-level function for downloading and parsing JSON from URLs.
143
144
```python { .api }
145
def request(http_client, url: str, headers: dict) -> dict: ...
146
```
147
148
**Parameters:**
149
- `http_client`: HTTP client instance
150
- `url` (str): URL to request
151
- `headers` (dict): HTTP headers to include
152
153
**Returns:**
154
- Parsed JSON response
155
156
#### is_file_scheme_uri
157
158
Check if a URL uses the file:// scheme.
159
160
```python { .api }
161
def is_file_scheme_uri(url: str) -> bool: ...
162
```
163
164
**Parameters:**
165
- `url` (str): URL to check
166
167
**Returns:**
168
- True if URL uses file:// scheme, False otherwise
169
170
## Loading Patterns
171
172
### Loading from URLs
173
174
```python
175
from bravado.swagger_model import load_url
176
from bravado.requests_client import RequestsClient
177
178
# Simple URL loading
179
spec_dict = load_url('https://petstore.swagger.io/v2/swagger.json')
180
181
# With custom HTTP client
182
http_client = RequestsClient()
183
http_client.set_api_key('api.example.com', 'your-api-key')
184
spec_dict = load_url('https://api.example.com/swagger.json', http_client=http_client)
185
186
# With base URL for relative references
187
spec_dict = load_url(
188
'https://api.example.com/swagger.json',
189
base_url='https://api.example.com'
190
)
191
```
192
193
### Loading from Local Files
194
195
```python
196
from bravado.swagger_model import load_file
197
198
# Load JSON file
199
spec_dict = load_file('/path/to/swagger.json')
200
201
# Load YAML file
202
spec_dict = load_file('/path/to/swagger.yaml')
203
204
# File scheme URLs
205
spec_dict = load_file('file:///path/to/swagger.json')
206
```
207
208
### Loading with Authentication
209
210
```python
211
from bravado.swagger_model import Loader
212
from bravado.requests_client import RequestsClient
213
214
# HTTP client with authentication
215
http_client = RequestsClient()
216
http_client.set_basic_auth('api.example.com', 'username', 'password')
217
218
# Loader with custom headers
219
loader = Loader(
220
http_client,
221
request_headers={
222
'User-Agent': 'MyApp/1.0',
223
'Accept': 'application/json,application/yaml'
224
}
225
)
226
227
spec_dict = loader.load_spec('https://api.example.com/swagger.json')
228
```
229
230
### Loading with Fallback
231
232
```python
233
from bravado.swagger_model import load_url, load_file
234
from bravado.exception import BravadoConnectionError
235
236
def load_spec_with_fallback(primary_url, fallback_file):
237
"""Load spec from URL with local file fallback."""
238
try:
239
return load_url(primary_url)
240
except BravadoConnectionError:
241
print(f"Failed to load from {primary_url}, using local fallback")
242
return load_file(fallback_file)
243
244
spec_dict = load_spec_with_fallback(
245
'https://api.example.com/swagger.json',
246
'/local/cache/swagger.json'
247
)
248
```
249
250
## Format Support
251
252
### JSON Support
253
254
All loading functions automatically handle JSON format specifications:
255
256
```python
257
# Standard JSON loading
258
spec_dict = load_url('https://api.example.com/swagger.json')
259
```
260
261
### YAML Support
262
263
YAML specifications are automatically detected and parsed:
264
265
```python
266
# YAML loading (detected by file extension or content)
267
spec_dict = load_url('https://api.example.com/swagger.yaml')
268
spec_dict = load_file('/path/to/swagger.yml')
269
270
# Direct YAML parsing
271
from bravado.swagger_model import Loader
272
273
loader = Loader(http_client)
274
yaml_content = """
275
openapi: 3.0.0
276
info:
277
title: My API
278
version: 1.0.0
279
paths:
280
/pets:
281
get:
282
responses:
283
'200':
284
description: Success
285
"""
286
spec_dict = loader.load_yaml(yaml_content)
287
```
288
289
## Remote References
290
291
The loading system automatically handles remote references ($ref) in specifications:
292
293
```python
294
# Spec with remote references will be automatically resolved
295
spec_dict = load_url('https://api.example.com/swagger.json')
296
297
# Custom headers are passed to remote reference requests
298
loader = Loader(
299
http_client,
300
request_headers={'Authorization': 'Bearer token123'}
301
)
302
spec_dict = loader.load_spec('https://api.example.com/swagger.json')
303
# Authorization header will be used for any remote $ref requests
304
```
305
306
## Error Handling
307
308
```python
309
from bravado.swagger_model import load_url, load_file
310
from bravado.exception import BravadoConnectionError, HTTPNotFound
311
import yaml
312
313
def safe_load_spec(spec_source):
314
"""Safely load specification with comprehensive error handling."""
315
try:
316
if spec_source.startswith('http'):
317
return load_url(spec_source)
318
else:
319
return load_file(spec_source)
320
321
except HTTPNotFound:
322
raise ValueError(f"Specification not found: {spec_source}")
323
324
except BravadoConnectionError as e:
325
raise ValueError(f"Cannot connect to load spec: {e}")
326
327
except yaml.YAMLError as e:
328
raise ValueError(f"Invalid YAML in specification: {e}")
329
330
except Exception as e:
331
raise ValueError(f"Failed to load specification: {e}")
332
333
# Usage with error handling
334
try:
335
spec_dict = safe_load_spec('https://api.example.com/swagger.yaml')
336
except ValueError as e:
337
print(f"Error loading spec: {e}")
338
# Handle error appropriately
339
```
340
341
## Performance Considerations
342
343
### Caching Loaded Specs
344
345
```python
346
import json
347
import os
348
from hashlib import md5
349
from bravado.swagger_model import load_url
350
351
class SpecCache:
352
def __init__(self, cache_dir='/tmp/swagger_cache'):
353
self.cache_dir = cache_dir
354
os.makedirs(cache_dir, exist_ok=True)
355
356
def get_cache_path(self, url):
357
url_hash = md5(url.encode()).hexdigest()
358
return os.path.join(self.cache_dir, f'{url_hash}.json')
359
360
def load_cached_or_fetch(self, url):
361
cache_path = self.get_cache_path(url)
362
363
if os.path.exists(cache_path):
364
with open(cache_path, 'r') as f:
365
return json.load(f)
366
367
# Cache miss, fetch and cache
368
spec_dict = load_url(url)
369
with open(cache_path, 'w') as f:
370
json.dump(spec_dict, f)
371
372
return spec_dict
373
374
# Usage
375
cache = SpecCache()
376
spec_dict = cache.load_cached_or_fetch('https://api.example.com/swagger.json')
377
```
378
379
### Async Loading (with FidoClient)
380
381
```python
382
from bravado.fido_client import FidoClient
383
from bravado.swagger_model import Loader
384
from twisted.internet import defer
385
386
@defer.inlineCallbacks
387
def load_spec_async(spec_url):
388
"""Load specification asynchronously using FidoClient."""
389
http_client = FidoClient()
390
loader = Loader(http_client)
391
392
spec_dict = yield loader.load_spec(spec_url)
393
defer.returnValue(spec_dict)
394
395
# Usage in Twisted application
396
def handle_spec_loaded(spec_dict):
397
print(f"Loaded spec with {len(spec_dict.get('paths', {}))} paths")
398
399
d = load_spec_async('https://api.example.com/swagger.json')
400
d.addCallback(handle_spec_loaded)
401
```