0
# Exception Handling
1
2
Complete HTTP status code exception hierarchy with timeout and connection error handling. Bravado provides specific exceptions for all HTTP status codes plus bravado-specific errors, enabling precise error handling for robust applications.
3
4
## Capabilities
5
6
### HTTPError (Base Exception)
7
8
Unified HTTP error base class that all HTTP-related exceptions inherit from. Contains response data and optional swagger result.
9
10
```python { .api }
11
class HTTPError(IOError):
12
status_code: int
13
def __init__(self, response, message: str = None, swagger_result=None): ...
14
def __str__(self) -> str: ...
15
```
16
17
**Attributes:**
18
- `status_code` (int): HTTP status code associated with this exception type
19
- `response`: IncomingResponse object containing the HTTP response details
20
- `message` (str): Optional custom error message
21
- `swagger_result`: Parsed response data if available
22
23
**Usage Example:**
24
25
```python
26
from bravado.exception import HTTPError, HTTPNotFound
27
28
try:
29
pet = client.pet.getPetById(petId=999).response().result
30
except HTTPNotFound as e:
31
print(f"Pet not found: {e}")
32
print(f"Status code: {e.status_code}")
33
print(f"Response body: {e.response.text}")
34
except HTTPError as e:
35
print(f"HTTP error {e.status_code}: {e}")
36
```
37
38
### Exception Hierarchy
39
40
Bravado organizes HTTP exceptions into logical categories:
41
42
#### HTTPRedirection (3xx)
43
44
Base class for 3xx redirection responses.
45
46
```python { .api }
47
class HTTPRedirection(HTTPError): ...
48
```
49
50
**Specific 3xx Exceptions:**
51
- `HTTPMultipleChoices` (300)
52
- `HTTPMovedPermanently` (301)
53
- `HTTPFound` (302)
54
- `HTTPSeeOther` (303)
55
- `HTTPNotModified` (304)
56
- `HTTPUseProxy` (305)
57
- `HTTPTemporaryRedirect` (307)
58
- `HTTPPermanentRedirect` (308)
59
60
#### HTTPClientError (4xx)
61
62
Base class for 4xx client error responses.
63
64
```python { .api }
65
class HTTPClientError(HTTPError): ...
66
```
67
68
**Common 4xx Exceptions:**
69
- `HTTPBadRequest` (400) - Invalid request syntax or parameters
70
- `HTTPUnauthorized` (401) - Authentication required or failed
71
- `HTTPPaymentRequired` (402) - Payment required
72
- `HTTPForbidden` (403) - Access denied
73
- `HTTPNotFound` (404) - Resource not found
74
- `HTTPMethodNotAllowed` (405) - HTTP method not supported
75
- `HTTPNotAcceptable` (406) - Cannot produce acceptable response
76
- `HTTPRequestTimeout` (408) - Request timeout
77
- `HTTPConflict` (409) - Request conflicts with current state
78
- `HTTPGone` (410) - Resource permanently removed
79
- `HTTPUnprocessableEntity` (422) - Validation errors
80
- `HTTPTooManyRequests` (429) - Rate limit exceeded
81
82
**All 4xx Exceptions:**
83
```python { .api }
84
class HTTPBadRequest(HTTPClientError): status_code = 400
85
class HTTPUnauthorized(HTTPClientError): status_code = 401
86
class HTTPPaymentRequired(HTTPClientError): status_code = 402
87
class HTTPForbidden(HTTPClientError): status_code = 403
88
class HTTPNotFound(HTTPClientError): status_code = 404
89
class HTTPMethodNotAllowed(HTTPClientError): status_code = 405
90
class HTTPNotAcceptable(HTTPClientError): status_code = 406
91
class HTTPProxyAuthenticationRequired(HTTPClientError): status_code = 407
92
class HTTPRequestTimeout(HTTPClientError): status_code = 408
93
class HTTPConflict(HTTPClientError): status_code = 409
94
class HTTPGone(HTTPClientError): status_code = 410
95
class HTTPLengthRequired(HTTPClientError): status_code = 411
96
class HTTPPreconditionFailed(HTTPClientError): status_code = 412
97
class HTTPPayloadTooLarge(HTTPClientError): status_code = 413
98
class HTTPURITooLong(HTTPClientError): status_code = 414
99
class HTTPUnsupportedMediaType(HTTPClientError): status_code = 415
100
class HTTPRangeNotSatisfiable(HTTPClientError): status_code = 416
101
class HTTPExpectationFailed(HTTPClientError): status_code = 417
102
class HTTPMisdirectedRequest(HTTPClientError): status_code = 421
103
class HTTPUnprocessableEntity(HTTPClientError): status_code = 422
104
class HTTPLocked(HTTPClientError): status_code = 423
105
class HTTPFailedDependency(HTTPClientError): status_code = 424
106
class HTTPUpgradeRequired(HTTPClientError): status_code = 426
107
class HTTPPreconditionRequired(HTTPClientError): status_code = 428
108
class HTTPTooManyRequests(HTTPClientError): status_code = 429
109
class HTTPRequestHeaderFieldsTooLarge(HTTPClientError): status_code = 431
110
class HTTPUnavailableForLegalReasons(HTTPClientError): status_code = 451
111
```
112
113
#### HTTPServerError (5xx)
114
115
Base class for 5xx server error responses. Includes response text in string representation for debugging.
116
117
```python { .api }
118
class HTTPServerError(HTTPError): ...
119
```
120
121
**Common 5xx Exceptions:**
122
- `HTTPInternalServerError` (500) - Server internal error
123
- `HTTPNotImplemented` (501) - Server does not support functionality
124
- `HTTPBadGateway` (502) - Invalid response from upstream server
125
- `HTTPServiceUnavailable` (503) - Server temporarily unavailable
126
- `HTTPGatewayTimeout` (504) - Upstream server timeout
127
- `HTTPHTTPVersionNotSupported` (505) - HTTP version not supported
128
129
**All 5xx Exceptions:**
130
```python { .api }
131
class HTTPInternalServerError(HTTPServerError): status_code = 500
132
class HTTPNotImplemented(HTTPServerError): status_code = 501
133
class HTTPBadGateway(HTTPServerError): status_code = 502
134
class HTTPServiceUnavailable(HTTPServerError): status_code = 503
135
class HTTPGatewayTimeout(HTTPServerError): status_code = 504
136
class HTTPHTTPVersionNotSupported(HTTPServerError): status_code = 505
137
class HTTPVariantAlsoNegotiates(HTTPServerError): status_code = 506
138
class HTTPInsufficientStorage(HTTPServerError): status_code = 507
139
class HTTPLoopDetected(HTTPServerError): status_code = 508
140
class HTTPNotExtended(HTTPServerError): status_code = 510
141
class HTTPNetworkAuthenticationRequired(HTTPServerError): status_code = 511
142
```
143
144
### Connection and Transport Errors
145
146
Bravado-specific exceptions for connection and transport-level issues.
147
148
```python { .api }
149
class BravadoTimeoutError(TimeoutError): ...
150
class BravadoConnectionError(ConnectionError): ...
151
class ForcedFallbackResultError(Exception): ...
152
```
153
154
**BravadoTimeoutError**: Raised when requests exceed configured timeout values.
155
**BravadoConnectionError**: Raised when connection to the server cannot be established.
156
**ForcedFallbackResultError**: Used internally to force fallback result behavior.
157
158
### Exception Factory Function
159
160
Utility function to create appropriate HTTP exceptions from responses.
161
162
```python { .api }
163
def make_http_exception(response, message: str = None, swagger_result=None) -> HTTPError: ...
164
```
165
166
**Parameters:**
167
- `response`: IncomingResponse object
168
- `message` (str): Optional custom error message
169
- `swagger_result`: Parsed response data if available
170
171
**Returns:**
172
- Appropriate HTTPError subclass instance based on status code
173
174
**Usage Example:**
175
176
```python
177
from bravado.exception import make_http_exception
178
179
# Manually create exception from response
180
try:
181
# ... some HTTP operation
182
pass
183
except Exception as e:
184
if hasattr(e, 'response'):
185
http_exception = make_http_exception(e.response, "Custom error message")
186
raise http_exception
187
```
188
189
### Status Code Mapping
190
191
All HTTP status codes are mapped to their corresponding exception classes:
192
193
```python { .api }
194
status_map: dict # Mapping of int status codes to exception classes
195
```
196
197
This dictionary maps HTTP status codes to their corresponding exception classes and is used internally by the exception factory.
198
199
## Error Handling Patterns
200
201
### Basic Exception Handling
202
203
```python
204
from bravado.exception import HTTPClientError, HTTPServerError, BravadoTimeoutError
205
206
try:
207
response = client.pet.getPetById(petId=1).response()
208
pet = response.result
209
except HTTPClientError as e:
210
if e.status_code == 404:
211
print("Pet not found")
212
elif e.status_code == 401:
213
print("Authentication required")
214
else:
215
print(f"Client error: {e.status_code}")
216
except HTTPServerError as e:
217
print(f"Server error: {e.status_code}")
218
print(f"Response: {e.response.text}")
219
except BravadoTimeoutError:
220
print("Request timed out")
221
```
222
223
### Specific Status Code Handling
224
225
```python
226
from bravado.exception import HTTPNotFound, HTTPUnauthorized, HTTPTooManyRequests
227
import time
228
229
try:
230
response = client.pet.getPetById(petId=1).response()
231
pet = response.result
232
except HTTPNotFound:
233
print("Pet does not exist")
234
pet = None
235
except HTTPUnauthorized:
236
print("Need to refresh authentication")
237
# Handle re-authentication
238
except HTTPTooManyRequests as e:
239
# Handle rate limiting
240
retry_after = int(e.response.headers.get('Retry-After', 60))
241
print(f"Rate limited, waiting {retry_after} seconds")
242
time.sleep(retry_after)
243
# Retry logic here
244
```
245
246
### Validation Error Handling
247
248
```python
249
from bravado.exception import HTTPBadRequest, HTTPUnprocessableEntity
250
251
try:
252
response = client.pet.addPet(body=new_pet_data).response()
253
pet = response.result
254
except HTTPBadRequest as e:
255
print("Invalid request format")
256
print(f"Error details: {e.response.text}")
257
except HTTPUnprocessableEntity as e:
258
print("Validation failed")
259
# Parse validation errors from response
260
errors = e.response.json().get('errors', [])
261
for error in errors:
262
print(f"Field {error['field']}: {error['message']}")
263
```
264
265
### Fallback with Exception Handling
266
267
```python
268
from bravado.exception import HTTPServerError, BravadoTimeoutError
269
270
# Combine fallback results with specific exception handling
271
try:
272
response = client.pet.getPetById(petId=1).response(
273
timeout=5.0,
274
fallback_result={'name': 'Unknown', 'status': 'unavailable'},
275
exceptions_to_catch=(BravadoTimeoutError, HTTPServerError)
276
)
277
278
if response.metadata.is_fallback_result:
279
print("Using fallback data due to service issues")
280
# Handle degraded functionality
281
282
pet = response.result
283
284
except HTTPNotFound:
285
# Still handle specific client errors that shouldn't use fallback
286
print("Pet definitely does not exist")
287
pet = None
288
```
289
290
### Logging and Monitoring
291
292
```python
293
import logging
294
from bravado.exception import HTTPError
295
296
logger = logging.getLogger(__name__)
297
298
try:
299
response = client.pet.getPetById(petId=1).response()
300
pet = response.result
301
except HTTPError as e:
302
# Log detailed error information for monitoring
303
logger.error(
304
"HTTP error in getPetById",
305
extra={
306
'status_code': e.status_code,
307
'pet_id': 1,
308
'response_body': e.response.text[:1000], # Truncate for logging
309
'response_headers': dict(e.response.headers),
310
}
311
)
312
raise # Re-raise for upstream handling
313
```
314
315
## Best Practices
316
317
1. **Catch Specific Exceptions**: Use specific exception types rather than generic HTTPError when possible
318
2. **Handle Expected Errors**: Plan for common API errors like 404, 401, 429
319
3. **Log Error Details**: Include status codes, response bodies, and request context in logs
320
4. **Use Fallback Results**: Consider fallback results for non-critical operations
321
5. **Retry Logic**: Implement appropriate retry logic for transient errors (5xx, timeouts)
322
6. **Rate Limiting**: Respect rate limit headers and implement backoff strategies
323
324
```python
325
# Good exception handling example
326
from bravado.exception import (
327
HTTPNotFound, HTTPUnauthorized, HTTPTooManyRequests,
328
HTTPServerError, BravadoTimeoutError
329
)
330
import time
331
import random
332
333
def get_pet_with_retry(client, pet_id, max_retries=3):
334
for attempt in range(max_retries + 1):
335
try:
336
response = client.pet.getPetById(petId=pet_id).response(timeout=10.0)
337
return response.result
338
339
except HTTPNotFound:
340
return None # Pet doesn't exist, don't retry
341
342
except HTTPUnauthorized:
343
# Handle re-authentication
344
refresh_auth(client)
345
continue
346
347
except HTTPTooManyRequests as e:
348
if attempt < max_retries:
349
# Exponential backoff with jitter
350
delay = (2 ** attempt) + random.uniform(0, 1)
351
time.sleep(delay)
352
continue
353
raise
354
355
except (HTTPServerError, BravadoTimeoutError) as e:
356
if attempt < max_retries:
357
# Retry transient errors
358
delay = (2 ** attempt) + random.uniform(0, 1)
359
time.sleep(delay)
360
continue
361
raise
362
363
raise Exception(f"Failed to get pet {pet_id} after {max_retries} retries")
364
```