feat: add comprehensive API error handling classes
Added new exception classes for API error handling including APIError, AuthenticationError, InvalidRequestError, APIConnectionError, RateLimitError, and ServerError to improve error handling and debugging capabilities in the SecureCompletionClient. These changes enhance the robustness of the API client by providing specific error types for different failure scenarios.
This commit is contained in:
parent
165f023513
commit
39c03fb975
3 changed files with 145 additions and 34 deletions
|
|
@ -9,11 +9,44 @@ from cryptography.hazmat.primitives.kdf.hkdf import HKDF
|
|||
# Setup module logger
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SecurityError(Exception):
|
||||
"""Raised when a security violation is detected."""
|
||||
pass
|
||||
|
||||
class APIError(Exception):
|
||||
"""Base class for all API-related errors."""
|
||||
def __init__(self, message: str, status_code: Optional[int] = None, error_details: Optional[Dict[str, Any]] = None):
|
||||
self.message = message
|
||||
self.status_code = status_code
|
||||
self.error_details = error_details
|
||||
super().__init__(message)
|
||||
|
||||
def __str__(self):
|
||||
return self.message
|
||||
|
||||
class AuthenticationError(APIError):
|
||||
"""Raised when authentication fails (e.g., invalid API key)."""
|
||||
def __init__(self, message: str, status_code: int = 401, error_details: Optional[Dict[str, Any]] = None):
|
||||
super().__init__(message, status_code, error_details)
|
||||
|
||||
class InvalidRequestError(APIError):
|
||||
"""Raised when the request is invalid (HTTP 400)."""
|
||||
def __init__(self, message: str, status_code: int = 400, error_details: Optional[Dict[str, Any]] = None):
|
||||
super().__init__(message, status_code, error_details)
|
||||
|
||||
class APIConnectionError(Exception):
|
||||
"""Raised when there's a connection error."""
|
||||
pass
|
||||
|
||||
class RateLimitError(APIError):
|
||||
"""Raised when rate limit is exceeded (HTTP 429)."""
|
||||
def __init__(self, message: str, status_code: int = 429, error_details: Optional[Dict[str, Any]] = None):
|
||||
super().__init__(message, status_code, error_details)
|
||||
|
||||
class ServerError(APIError):
|
||||
"""Raised when the server returns an error (HTTP 500)."""
|
||||
def __init__(self, message: str, status_code: int = 500, error_details: Optional[Dict[str, Any]] = None):
|
||||
super().__init__(message, status_code, error_details)
|
||||
|
||||
class SecureCompletionClient:
|
||||
"""
|
||||
|
|
@ -449,6 +482,13 @@ class SecureCompletionClient:
|
|||
|
||||
Returns:
|
||||
Decrypted response from the LLM
|
||||
|
||||
Raises:
|
||||
AuthenticationError: If API key is invalid or missing (HTTP 401)
|
||||
InvalidRequestError: If the request is invalid (HTTP 400)
|
||||
APIError: For other HTTP errors
|
||||
APIConnectionError: If connection fails
|
||||
SecurityError: If encryption/decryption fails
|
||||
"""
|
||||
logger.info("Sending secure chat completion request...")
|
||||
|
||||
|
|
@ -487,23 +527,76 @@ class SecureCompletionClient:
|
|||
return decrypted_response
|
||||
|
||||
elif response.status_code == 400:
|
||||
error = response.json()
|
||||
raise ValueError(f"Bad request: {error.get('detail', 'Unknown error')}")
|
||||
# Bad request
|
||||
try:
|
||||
error = response.json()
|
||||
raise InvalidRequestError(
|
||||
f"Bad request: {error.get('detail', 'Unknown error')}",
|
||||
status_code=400,
|
||||
error_details=error
|
||||
)
|
||||
except (json.JSONDecodeError, ValueError):
|
||||
raise InvalidRequestError("Bad request: Invalid response format")
|
||||
|
||||
elif response.status_code == 401:
|
||||
# Unauthorized - authentication failed
|
||||
try:
|
||||
error = response.json()
|
||||
error_message = error.get('detail', 'Invalid API key or authentication failed')
|
||||
raise AuthenticationError(
|
||||
error_message,
|
||||
status_code=401,
|
||||
error_details=error
|
||||
)
|
||||
except (json.JSONDecodeError, ValueError):
|
||||
raise AuthenticationError("Invalid API key or authentication failed")
|
||||
|
||||
elif response.status_code == 404:
|
||||
error = response.json()
|
||||
raise ValueError(f"Endpoint not found: {error.get('detail', 'Secure inference not enabled')}")
|
||||
# Endpoint not found
|
||||
try:
|
||||
error = response.json()
|
||||
raise APIError(
|
||||
f"Endpoint not found: {error.get('detail', 'Secure inference not enabled')}",
|
||||
status_code=404,
|
||||
error_details=error
|
||||
)
|
||||
except (json.JSONDecodeError, ValueError):
|
||||
raise APIError("Endpoint not found: Secure inference not enabled")
|
||||
|
||||
elif response.status_code == 429:
|
||||
# Rate limit exceeded
|
||||
try:
|
||||
error = response.json()
|
||||
raise RateLimitError(
|
||||
f"Rate limit exceeded: {error.get('detail', 'Too many requests')}",
|
||||
status_code=429,
|
||||
error_details=error
|
||||
)
|
||||
except (json.JSONDecodeError, ValueError):
|
||||
raise RateLimitError("Rate limit exceeded: Too many requests")
|
||||
|
||||
elif response.status_code == 500:
|
||||
error = response.json()
|
||||
raise ValueError(f"Server error: {error.get('detail', 'Internal server error')}")
|
||||
# Server error
|
||||
try:
|
||||
error = response.json()
|
||||
raise ServerError(
|
||||
f"Server error: {error.get('detail', 'Internal server error')}",
|
||||
status_code=500,
|
||||
error_details=error
|
||||
)
|
||||
except (json.JSONDecodeError, ValueError):
|
||||
raise ServerError("Server error: Internal server error")
|
||||
|
||||
else:
|
||||
raise ValueError(f"Unexpected status code: {response.status_code}")
|
||||
# Unexpected status code
|
||||
raise APIError(
|
||||
f"Unexpected status code: {response.status_code}",
|
||||
status_code=response.status_code
|
||||
)
|
||||
|
||||
except httpx.NetworkError as e:
|
||||
raise ConnectionError(f"Failed to connect to router: {e}")
|
||||
except (ValueError, SecurityError, ConnectionError):
|
||||
raise APIConnectionError(f"Failed to connect to router: {e}")
|
||||
except (SecurityError, APIError, AuthenticationError, InvalidRequestError, RateLimitError, ServerError, APIConnectionError):
|
||||
raise # Re-raise known exceptions
|
||||
except Exception as e:
|
||||
raise Exception(f"Request failed: {e}")
|
||||
|
|
|
|||
|
|
@ -5,6 +5,24 @@ OpenAI-compatible secure chat client with end-to-end encryption.
|
|||
"""
|
||||
|
||||
from .nomyo import SecureChatCompletion
|
||||
from .SecureCompletionClient import (
|
||||
APIError,
|
||||
AuthenticationError,
|
||||
InvalidRequestError,
|
||||
APIConnectionError,
|
||||
RateLimitError,
|
||||
ServerError
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
'SecureChatCompletion',
|
||||
'APIError',
|
||||
'AuthenticationError',
|
||||
'InvalidRequestError',
|
||||
'APIConnectionError',
|
||||
'RateLimitError',
|
||||
'ServerError'
|
||||
]
|
||||
|
||||
__version__ = "0.1.0"
|
||||
__author__ = "NOMYO AI"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import uuid
|
||||
from typing import Dict, Any, List, Optional
|
||||
from .SecureCompletionClient import SecureCompletionClient
|
||||
from .SecureCompletionClient import SecureCompletionClient, APIError, AuthenticationError, InvalidRequestError, APIConnectionError, RateLimitError, ServerError
|
||||
|
||||
class SecureChatCompletion:
|
||||
"""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue