Library for accessing Swagger-enabled APIs
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Flexible configuration system for both global bravado settings and per-request options. The configuration system supports response metadata customization, timeout configuration, callback mechanisms, and extensive behavioral controls.
Global configuration object that controls bravado's behavior across all requests. Uses a NamedTuple structure for type safety and immutability.
class BravadoConfig:
also_return_response: bool
disable_fallback_results: bool
response_metadata_class: Type[BravadoResponseMetadata]
sensitive_headers: listAttributes:
also_return_response (bool): Whether operations should return BravadoResponse objects with metadatadisable_fallback_results (bool): Kill switch to disable fallback results even if providedresponse_metadata_class (Type): Class to use for response metadata objectssensitive_headers (list): List of header names to exclude from debug logsPer-request configuration that allows fine-grained control over individual API operations.
class RequestConfig:
also_return_response: bool
force_fallback_result: bool
response_callbacks: list
connect_timeout: float
timeout: float
headers: dict
use_msgpack: bool
additional_properties: dict
def __init__(self, request_options: dict, also_return_response_default: bool): ...Attributes:
also_return_response (bool): Override global setting for this requestforce_fallback_result (bool): Force fallback result regardless of successresponse_callbacks (list): Functions to call during response processingconnect_timeout (float): Connection timeout in secondstimeout (float): Request timeout in secondsheaders (dict): Additional headers for this requestuse_msgpack (bool): Use MessagePack encoding for request/responseadditional_properties (dict): Custom properties for extensionsUsage Example:
from bravado.config import RequestConfig
# Create per-request configuration
request_config = RequestConfig({
'timeout': 30.0,
'headers': {'X-Custom-Header': 'value'},
'use_msgpack': True
}, also_return_response_default=False)
# Use with operation
response = client.pet.getPetById(petId=1, _request_config=request_config).response()Default configuration values used when no explicit configuration is provided.
CONFIG_DEFAULTS: dict = {
'also_return_response': False,
'disable_fallback_results': False,
'response_metadata_class': 'bravado.response.BravadoResponseMetadata',
'sensitive_headers': ['Authorization']
}These defaults provide sensible behavior for most use cases while allowing full customization.
Utility function to create BravadoConfig objects from dictionary configurations.
def bravado_config_from_config_dict(config_dict: dict) -> BravadoConfig: ...Parameters:
config_dict (dict): Configuration dictionary with bravado settingsReturns:
Usage Example:
from bravado.config import bravado_config_from_config_dict
config_dict = {
'also_return_response': True,
'disable_fallback_results': False,
'sensitive_headers': ['Authorization', 'X-API-Key']
}
bravado_config = bravado_config_from_config_dict(config_dict)Configure bravado behavior globally when creating SwaggerClient instances:
from bravado.client import SwaggerClient
# Global configuration
config = {
# Bravado-specific settings
'also_return_response': True,
'disable_fallback_results': False,
'response_metadata_class': 'bravado.response.BravadoResponseMetadata',
'sensitive_headers': ['Authorization', 'X-Secret-Key'],
# bravado-core settings (validation, models, etc.)
'validate_requests': True,
'validate_responses': True,
'use_models': True,
'validate_swagger_spec': True,
'formats': [], # Custom format validators
}
client = SwaggerClient.from_url(spec_url, config=config)You can provide a custom response metadata class:
from bravado.response import BravadoResponseMetadata
class CustomResponseMetadata(BravadoResponseMetadata):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.custom_field = "custom_value"
@property
def custom_property(self):
return f"Request took {self.elapsed_time:.2f}s"
config = {
'response_metadata_class': 'myapp.CustomResponseMetadata'
}
client = SwaggerClient.from_url(spec_url, config=config)Override global settings for specific requests using RequestConfig:
from bravado.config import RequestConfig
# Timeout configuration
timeout_config = RequestConfig({
'timeout': 60.0, # 60 second timeout
'connect_timeout': 10.0 # 10 second connection timeout
}, also_return_response_default=False)
# Custom headers
headers_config = RequestConfig({
'headers': {
'X-Request-ID': 'req-12345',
'X-Client-Version': '1.0.0'
}
}, also_return_response_default=False)
# Use configurations
response1 = client.pet.getPetById(petId=1, _request_config=timeout_config).response()
response2 = client.pet.addPet(body=pet_data, _request_config=headers_config).response()Execute custom logic during response processing:
def log_request_time(response, operation):
print(f"Operation {operation.operation_id} took {response.elapsed_time:.2f}s")
def validate_custom_header(response, operation):
if 'X-Custom-Header' not in response.headers:
print("Warning: Expected custom header missing")
callback_config = RequestConfig({
'response_callbacks': [log_request_time, validate_custom_header]
}, also_return_response_default=True)
response = client.pet.getPetById(petId=1, _request_config=callback_config).response()Use MessagePack encoding for better performance with large payloads:
msgpack_config = RequestConfig({
'use_msgpack': True,
'headers': {'Accept': 'application/msgpack'}
}, also_return_response_default=False)
# Request and response will use MessagePack encoding
response = client.pet.addPet(body=large_pet_data, _request_config=msgpack_config).response()import os
from bravado.client import SwaggerClient
def create_client(spec_url):
config = {
'also_return_response': os.getenv('BRAVADO_RETURN_RESPONSE', 'false').lower() == 'true',
'validate_requests': os.getenv('BRAVADO_VALIDATE_REQUESTS', 'true').lower() == 'true',
'validate_responses': os.getenv('BRAVADO_VALIDATE_RESPONSES', 'true').lower() == 'true',
}
# Development vs production settings
if os.getenv('ENVIRONMENT') == 'development':
config.update({
'validate_swagger_spec': True,
'sensitive_headers': ['Authorization'] # More logging in dev
})
else:
config.update({
'validate_swagger_spec': False, # Skip validation in production
'sensitive_headers': ['Authorization', 'X-API-Key', 'Cookie']
})
return SwaggerClient.from_url(spec_url, config=config)from dataclasses import dataclass
from bravado.config import RequestConfig
@dataclass
class RequestProfile:
timeout: float
connect_timeout: float
retries: int
def to_request_config(self):
return RequestConfig({
'timeout': self.timeout,
'connect_timeout': self.connect_timeout,
'additional_properties': {'retries': self.retries}
}, also_return_response_default=True)
# Define profiles
PROFILES = {
'fast': RequestProfile(timeout=5.0, connect_timeout=2.0, retries=1),
'standard': RequestProfile(timeout=30.0, connect_timeout=10.0, retries=3),
'slow': RequestProfile(timeout=120.0, connect_timeout=30.0, retries=5)
}
# Use profiles
fast_config = PROFILES['fast'].to_request_config()
response = client.pet.getPetById(petId=1, _request_config=fast_config).response()from bravado.config import bravado_config_from_config_dict
def validate_config(config_dict):
"""Validate configuration before creating client."""
required_keys = ['also_return_response', 'validate_requests']
for key in required_keys:
if key not in config_dict:
raise ValueError(f"Missing required config key: {key}")
if config_dict.get('timeout', 0) <= 0:
raise ValueError("Timeout must be positive")
return bravado_config_from_config_dict(config_dict)
# Use validation
try:
config = validate_config({
'also_return_response': True,
'validate_requests': True,
'timeout': 30.0
})
client = SwaggerClient.from_url(spec_url, config=config._asdict())
except ValueError as e:
print(f"Configuration error: {e}")# Good configuration example
import os
from bravado.client import SwaggerClient
from bravado.requests_client import RequestsClient
def create_production_client(spec_url):
# Production-optimized HTTP client
http_client = RequestsClient(
ssl_verify=True, # Always verify SSL in production
)
# Production configuration
config = {
'also_return_response': True, # Always get metadata for monitoring
'validate_requests': True, # Validate requests to catch issues early
'validate_responses': False, # Skip response validation for performance
'validate_swagger_spec': False, # Skip spec validation for startup performance
'sensitive_headers': [ # Comprehensive sensitive header list
'Authorization', 'X-API-Key', 'Cookie',
'X-Auth-Token', 'X-Session-ID'
]
}
return SwaggerClient.from_url(spec_url, http_client=http_client, config=config)
def create_development_client(spec_url):
config = {
'also_return_response': True,
'validate_requests': True, # Full validation in development
'validate_responses': True,
'validate_swagger_spec': True,
'sensitive_headers': ['Authorization'] # Minimal for easier debugging
}
return SwaggerClient.from_url(spec_url, config=config)
# Use environment-based client creation
if os.getenv('ENVIRONMENT') == 'production':
client = create_production_client(spec_url)
else:
client = create_development_client(spec_url)Install with Tessl CLI
npx tessl i tessl/pypi-bravado