Exceptions

La bibliothèque fournit une hiérarchie d’exceptions personnalisées pour gérer différents types d’erreurs.

Hiérarchie des exceptions

ArzekaPaymentError (Exception de base)
├── ArzekaValidationError
├── ArzekaAuthenticationError
├── ArzekaAPIError
├── ArzekaConnectionError
└── ArzekaTimeoutError

Toutes les exceptions héritent de ArzekaPaymentError, ce qui permet de les capturer toutes en une fois si nécessaire.

ArzekaPaymentError

Exception de base pour toutes les erreurs de la bibliothèque.

class ArzekaPaymentError(Exception):
    """Exception de base pour toutes les erreurs Arzeka"""

Utilisation:

from fasoarzeka import ArzekaPaymentError

try:
    # ... opérations Arzeka
    pass
except ArzekaPaymentError as e:
    print(f"Erreur Arzeka : {e}")

ArzekaValidationError

Levée lorsque les données fournies sont invalides.

Causes courantes:

  • Montant invalide (< 100 ou non numérique)

  • Numéro de téléphone invalide

  • Paramètres manquants ou incorrects

  • Format de données incorrect

Exemple:

from fasoarzeka import ArzekaPayment, ArzekaValidationError

client = ArzekaPayment()
client.authenticate("username", "password")

try:
    # Montant trop petit
    response = client.initiate_payment(
        amount=50,  # < 100 FCFA
        merchant_id="MERCHANT_123",
        # ... autres paramètres
    )
except ArzekaValidationError as e:
    print(f"Données invalides : {e}")

ArzekaAuthenticationError

Levée lors d’un échec d’authentification.

Causes courantes:

  • Identifiants incorrects (username/password)

  • Token expiré

  • Token invalide

  • Compte verrouillé ou désactivé

Exemple:

from fasoarzeka import ArzekaPayment, ArzekaAuthenticationError

client = ArzekaPayment()

try:
    client.authenticate("wrong_user", "wrong_password")
except ArzekaAuthenticationError as e:
    print(f"Authentification échouée : {e}")
    # Demander à l'utilisateur de réessayer

Avec réauthentification automatique:

try:
    response = client.initiate_payment(...)
except ArzekaAuthenticationError as e:
    # Token expiré et pas de credentials stockés
    print(f"Réauthentification requise : {e}")
    client.authenticate("username", "password")
    response = client.initiate_payment(...)

ArzekaAPIError

Levée lorsque l’API Arzeka retourne une erreur.

Attributs:

  • status_code (int) : Code de statut HTTP (400, 404, 500, etc.)

  • response_data (dict) : Données de réponse de l’API

  • message (str) : Message d’erreur

Causes courantes:

  • Erreur serveur (500, 502, 503)

  • Ressource introuvable (404)

  • Requête invalide (400)

  • Limite de taux dépassée (429)

  • Problème de paiement (solde insuffisant, etc.)

Exemple:

from fasoarzeka import check_payment, ArzekaAPIError

try:
    status = check_payment("INVALID_ORDER_ID")
except ArzekaAPIError as e:
    print(f"Erreur API : {e}")
    print(f"Code HTTP : {e.status_code}")
    print(f"Détails : {e.response_data}")

    if e.status_code == 404:
        print("Commande introuvable")
    elif e.status_code == 500:
        print("Erreur serveur, réessayer plus tard")

Gestion par code de statut:

try:
    response = client.initiate_payment(...)
except ArzekaAPIError as e:
    if e.status_code == 400:
        print("Requête invalide")
    elif e.status_code == 401:
        print("Non autorisé")
    elif e.status_code == 404:
        print("Ressource introuvable")
    elif e.status_code >= 500:
        print("Erreur serveur")
    else:
        print(f"Erreur API : {e}")

ArzekaConnectionError

Levée lors d’un problème de connexion réseau.

Causes courantes:

  • Pas de connexion Internet

  • Serveur inaccessible

  • DNS ne résout pas

  • Firewall bloquant la connexion

Exemple:

from fasoarzeka import authenticate, ArzekaConnectionError
import time

max_retries = 3

for attempt in range(max_retries):
    try:
        auth = authenticate("username", "password")
        print("✅ Connexion réussie")
        break
    except ArzekaConnectionError as e:
        print(f"❌ Erreur de connexion (tentative {attempt+1}/{max_retries})")
        if attempt < max_retries - 1:
            time.sleep(2 ** attempt)  # Backoff exponentiel
        else:
            print("Impossible de se connecter après plusieurs tentatives")
            raise

ArzekaTimeoutError

Levée lorsqu’une requête dépasse le timeout configuré.

Causes courantes:

  • Serveur lent ou surchargé

  • Problème réseau intermittent

  • Timeout configuré trop court

Exemple:

from fasoarzeka import ArzekaPayment, ArzekaTimeoutError

client = ArzekaPayment(timeout=5)  # 5 secondes

try:
    response = client.initiate_payment(...)
except ArzekaTimeoutError as e:
    print(f"Timeout : {e}")
    # Réessayer avec un timeout plus long
    client.timeout = 30
    response = client.initiate_payment(...)

Gestion globale des erreurs

Approche simple

Capturer toutes les exceptions Arzeka :

from fasoarzeka import ArzekaPayment, ArzekaPaymentError

client = ArzekaPayment()

try:
    client.authenticate("username", "password")
    response = client.initiate_payment(...)
except ArzekaPaymentError as e:
    print(f"Erreur : {e}")
    # Logger l'erreur
    logger.error(f"Arzeka error: {e}")

Approche détaillée

Gérer chaque type d’erreur différemment :

from fasoarzeka import (
    ArzekaPayment,
    ArzekaValidationError,
    ArzekaAuthenticationError,
    ArzekaAPIError,
    ArzekaConnectionError,
    ArzekaTimeoutError
)

client = ArzekaPayment()

try:
    client.authenticate("username", "password")
    response = client.initiate_payment(
        amount=1000,
        merchant_id="MERCHANT_123",
        # ... autres paramètres
    )

except ArzekaValidationError as e:
    print(f"❌ Données invalides : {e}")
    # Corriger les données et réessayer

except ArzekaAuthenticationError as e:
    print(f"❌ Authentification échouée : {e}")
    # Demander de nouveaux identifiants

except ArzekaAPIError as e:
    print(f"❌ Erreur API (code {e.status_code}) : {e}")
    # Logger et alerter

except ArzekaConnectionError as e:
    print(f"❌ Erreur de connexion : {e}")
    # Réessayer plus tard

except ArzekaTimeoutError as e:
    print(f"❌ Timeout : {e}")
    # Réessayer avec timeout plus long

Fonction de retry

Créer une fonction de retry personnalisée :

import time
from fasoarzeka import (
    ArzekaPayment,
    ArzekaConnectionError,
    ArzekaTimeoutError,
    ArzekaAPIError
)

def retry_operation(func, max_retries=3, delay=2):
    """Réessayer une opération en cas d'erreur temporaire"""
    for attempt in range(max_retries):
        try:
            return func()
        except (ArzekaConnectionError, ArzekaTimeoutError) as e:
            if attempt < max_retries - 1:
                print(f"⚠️ Tentative {attempt+1} échouée, réessai dans {delay}s...")
                time.sleep(delay)
                delay *= 2  # Backoff exponentiel
            else:
                print(f"❌ Échec après {max_retries} tentatives")
                raise
        except ArzekaAPIError as e:
            # Ne pas réessayer sur erreur API 4xx (erreur client)
            if 400 <= e.status_code < 500:
                raise
            # Réessayer sur erreur 5xx (erreur serveur)
            if attempt < max_retries - 1:
                print(f"⚠️ Erreur serveur, réessai dans {delay}s...")
                time.sleep(delay)
            else:
                raise

# Utilisation
client = ArzekaPayment()
client.authenticate("username", "password")

def do_payment():
    return client.initiate_payment(...)

response = retry_operation(do_payment)

Logging des erreurs

Configuration de base

import logging
from fasoarzeka import ArzekaPayment, ArzekaPaymentError

# Configurer le logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

client = ArzekaPayment()

try:
    client.authenticate("username", "password")
    response = client.initiate_payment(...)
except ArzekaPaymentError as e:
    logger.error(f"Arzeka error: {e}", exc_info=True)

Logging détaillé par type d’erreur

from fasoarzeka import (
    ArzekaValidationError,
    ArzekaAuthenticationError,
    ArzekaAPIError,
    ArzekaConnectionError
)

try:
    response = client.initiate_payment(...)
except ArzekaValidationError as e:
    logger.warning(f"Validation error: {e}")
except ArzekaAuthenticationError as e:
    logger.error(f"Authentication failed: {e}")
except ArzekaAPIError as e:
    logger.error(
        f"API error: {e}",
        extra={
            'status_code': e.status_code,
            'response_data': e.response_data
        }
    )
except ArzekaConnectionError as e:
    logger.critical(f"Connection error: {e}")

Meilleures pratiques

  1. Toujours capturer les exceptions spécifiques

    # ✅ BON
    try:
         response = client.initiate_payment(...)
     except ArzekaValidationError:
         # Gérer erreur de validation
     except ArzekaAPIError:
         # Gérer erreur API
    
    # ❌ MAUVAIS
    try:
         response = client.initiate_payment(...)
     except Exception:
         # Trop général
    
  2. Logger toutes les erreurs

    import logging
    
    try:
         response = client.initiate_payment(...)
     except ArzekaPaymentError as e:
         logger.error(f"Payment failed: {e}", exc_info=True)
         raise
    
  3. Fournir des messages utilisateur clairs

    try:
         response = client.initiate_payment(...)
     except ArzekaValidationError:
         return "Vérifiez vos informations de paiement"
     except ArzekaConnectionError:
         return "Problème de connexion, réessayez plus tard"
     except ArzekaAPIError as e:
         if e.status_code == 404:
             return "Paiement introuvable"
         return "Erreur lors du traitement du paiement"
    
  4. Implémenter un système de retry

    Pour les erreurs temporaires (connexion, timeout, erreur serveur), implémentez un système de retry avec backoff exponentiel.

  5. Monitorer les erreurs

    Utilisez un système de monitoring (Sentry, Datadog, etc.) pour suivre les erreurs en production.

Voir aussi