Error Handling¶
The DevHub SDK provides comprehensive error handling to help you build robust applications.
Exception Types¶
The SDK uses a hierarchy of exceptions for different error scenarios:
All SDK exceptions inherit from DevoException
, making it easy to catch any SDK-related error.
Basic Error Handling¶
Simple Try-Catch¶
from devhub_python.exceptions import DevoException
try:
sms_response = client.sms.send_sms(
recipient="+1234567890",
message="Hello!",
sender="+1987654321"
)
print(f"Success: {sms_response.id}")
except DevoException as e:
print(f"Error: {e}")
Checking Response Status¶
# Some API responses include status information
sms_response = client.sms.send_sms(
recipient="+1234567890",
message="Hello!",
sender="+1987654321"
)
# Check if the response indicates an error
if hasattr(sms_response, 'is_error') and sms_response.is_error():
print(f"API returned error: {sms_response.statusCode}")
else:
print(f"Message sent successfully: {sms_response.id}")
Common Error Scenarios¶
Invalid Phone Numbers¶
try:
response = client.sms.send_sms(
recipient="invalid-number", # Invalid format
message="Test",
sender="+1987654321"
)
except DevoException as e:
print(f"Invalid phone number: {e}")
Authentication Errors¶
# Wrong API key
client = DevoClient(api_key="invalid-key")
try:
response = client.sms.send_sms(
recipient="+1234567890",
message="Test",
sender="+1987654321"
)
except DevoException as e:
print(f"Authentication failed: {e}")
Missing Required Fields¶
from devhub_python.models.contacts import CreateContactDto
try:
# Missing required data
contact_data = CreateContactDto() # No required fields
contact = client.services.contacts.create(contact_data)
except DevoException as e:
print(f"Validation error: {e}")
Retry Logic¶
Simple Retry Pattern¶
import time
from devhub_python.exceptions import DevoException
def send_with_retry(client, recipient, message, max_retries=3):
for attempt in range(max_retries):
try:
return client.sms.send_sms(
recipient=recipient,
message=message,
sender="+1987654321"
)
except DevoException as e:
print(f"Attempt {attempt + 1} failed: {e}")
if attempt < max_retries - 1:
time.sleep(1) # Wait 1 second before retry
continue
else:
raise # Re-raise the last exception
Exponential Backoff¶
import time
import random
from devhub_python.exceptions import DevoException
def send_with_backoff(client, recipient, message, max_retries=3):
for attempt in range(max_retries):
try:
return client.sms.send_sms(
recipient=recipient,
message=message,
sender="+1987654321"
)
except DevoException as e:
if attempt < max_retries - 1:
# Exponential backoff with jitter
delay = (2 ** attempt) + random.uniform(0, 1)
print(f"Attempt {attempt + 1} failed, retrying in {delay:.2f}s: {e}")
time.sleep(delay)
continue
else:
raise
Graceful Degradation¶
Fallback to Alternative Channels¶
from devhub_python.exceptions import DevoException
def send_message_with_fallback(client, recipient, message):
"""Try SMS first, fallback to WhatsApp if SMS fails."""
# Try SMS first
try:
response = client.sms.send_sms(
recipient=recipient,
message=message,
sender="+1987654321"
)
return {"channel": "sms", "response": response}
except DevoException as sms_error:
print(f"SMS failed: {sms_error}")
# Fallback to WhatsApp
try:
response = client.whatsapp.send_text_message(
recipient=recipient,
message=message
)
return {"channel": "whatsapp", "response": response}
except DevoException as whatsapp_error:
print(f"WhatsApp also failed: {whatsapp_error}")
raise DevoException("All channels failed") from whatsapp_error
# Usage
try:
result = send_message_with_fallback(client, "+1234567890", "Important message!")
print(f"Message sent via {result['channel']}: {result['response'].id}")
except DevoException as e:
print(f"Could not send message: {e}")
Logging Errors¶
Basic Logging¶
import logging
from devhub_python.exceptions import DevoException
# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def send_message_with_logging(client, recipient, message):
try:
logger.info(f"Sending SMS to {recipient}")
response = client.sms.send_sms(
recipient=recipient,
message=message,
sender="+1987654321"
)
logger.info(f"SMS sent successfully: {response.id}")
return response
except DevoException as e:
logger.error(f"SMS sending failed: {e}", exc_info=True)
raise
Best Practices¶
1. Always Use Try-Catch¶
# Good
try:
response = client.sms.send_sms(recipient, message, sender)
except DevoException as e:
handle_error(e)
# Bad - no error handling
response = client.sms.send_sms(recipient, message, sender)
2. Validate Input Early¶
def send_sms_safe(client, recipient, message, sender):
# Validate inputs before making API call
if not recipient or not recipient.startswith('+'):
raise ValueError("Recipient must be in E.164 format")
if not message or len(message.strip()) == 0:
raise ValueError("Message cannot be empty")
if not sender or not sender.startswith('+'):
raise ValueError("Sender must be in E.164 format")
try:
return client.sms.send_sms(recipient, message, sender)
except DevoException as e:
logger.error(f"SMS API error: {e}")
raise
3. Handle Partial Failures¶
def send_bulk_messages(client, recipients, message):
results = []
failed = []
for recipient in recipients:
try:
response = client.sms.send_sms(recipient, message, "+1987654321")
results.append({"recipient": recipient, "status": "success", "id": response.id})
except DevoException as e:
failed.append({"recipient": recipient, "error": str(e)})
return {
"successful": results,
"failed": failed,
"total": len(recipients),
"success_rate": len(results) / len(recipients)
}
Rate Limits
Be mindful of API rate limits when implementing retry logic. Use exponential backoff to avoid overwhelming the API.