Intermédiaire

Gestion des erreurs réseau

Un appel HTTP peut échouer pour de nombreuses raisons : API éteinte, réseau coupé, timeout, paramètres invalides... Le dashboard doit gérer tous ces cas sans crasher.

Deux catégories d'erreurs

Les erreurs HTTP se divisent en deux catégories :

CatégorieCauseConséquence en Python
Erreurs réseauL'appel HTTP échoue complètementException Python levée par requests
Erreurs HTTPL'appel atteint le serveur mais il retourne un code d'erreurPas d'exception — il faut vérifier status_code

Distinction cruciale

requests.get() ne lève jamais d'exception pour un code HTTP 400 ou 500. L'appel a techniquement réussi (le serveur a répondu). Seules les erreurs réseau (API inaccessible, timeout) lèvent des exceptions.

Erreurs réseau : les exceptions requests

Les principales exceptions levées par requests quand l'appel échoue :

SituationExceptionExemple
API éteinte / inaccessibleConnectionErrorLe serveur Flask n'est pas lancé
Délai dépasséTimeoutLe serveur ne répond pas dans le délai imparti
Mauvais paramètre côté serveurCode 400 (pas d'exception)Paramètre invalide envoyé à l'API
Ressource inexistanteCode 404 (pas d'exception)Endpoint ou donnée non trouvé
Erreur interne du serveurCode 500 (pas d'exception)Bug dans le code Flask

Gérer les exceptions réseau

python
import requests
import streamlit as st

url = "http://localhost:5000/api/v1/ventes/par-region"

try:
    response = requests.get(url, timeout=5)  # TOUJOURS spécifier un timeout
except requests.exceptions.ConnectionError:
    st.error("Impossible de joindre l'API. Vérifiez que le serveur Flask est lancé.")
    st.stop()
except requests.exceptions.Timeout:
    st.error("L'API ne répond pas dans les délais. Réessayez plus tard.")
    st.stop()
except requests.exceptions.RequestException as e:
    st.error(f"Erreur réseau inattendue : {e}")
    st.stop()

Toujours spécifier un timeout

Sans timeout, requests.get() attend indéfiniment si le serveur ne répond pas. Votre dashboard Streamlit serait alors figé sans aucun message d'erreur. Spécifiez toujours un timeout en secondes.

st.stop() : arrêter l'exécution

st.stop() arrête l'exécution du script Streamlit à cet endroit. C'est l'équivalent d'un return dans une fonction : tout le code après st.stop() n'est pas exécuté.

Inutile de continuer à afficher des graphiques si les données n'ont pas pu être récupérées.

Que se passe-t-il si vous n'ajoutez pas de timeout à requests.get() et que le serveur ne répond pas ?

Erreurs HTTP : vérifier le code de retour

Quand l'appel HTTP atteint le serveur mais que celui-ci retourne une erreur (400, 404, 500...), requests ne lève pas d'exception. Il faut vérifier manuellement.

Option 1 : vérification manuelle avec response.ok

python
response = requests.get(url, timeout=5)

if not response.ok:
    st.error(f"Erreur API (code {response.status_code})")
    st.stop()

data = response.json()

Option 2 : raise_for_status()

La méthode raise_for_status() lève une exception HTTPError si le code de retour est supérieur ou égal à 400 :

python
try:
    response = requests.get(url, timeout=5)
    response.raise_for_status()  # Lève HTTPError si code >= 400
except requests.exceptions.HTTPError as e:
    if response.status_code == 404:
        st.warning("Aucune donnée trouvée pour ces critères.")
    elif response.status_code == 400:
        st.error("Paramètres invalides. Vérifiez vos filtres.")
    elif response.status_code >= 500:
        st.error("Erreur serveur. Contactez l'administrateur.")
    st.stop()

raise_for_status() est recommandé

raise_for_status() permet de traiter les erreurs réseau et HTTP dans le même bloc try/except. Le code est plus lisible.

Que fait response.raise_for_status() si le code HTTP est 200 ?

Pattern complet : la fonction api_get

Plutôt que de répéter la gestion d'erreurs à chaque appel, centralisez-la dans une fonction :

python
import requests
import streamlit as st


def api_get(endpoint: str, params: dict = None) -> dict | None:
    """Appelle un endpoint GET de l'API et retourne le JSON, ou None en cas d'erreur."""
    base_url = "http://localhost:5000/api/v1"

    try:
        response = requests.get(f"{base_url}/{endpoint}", params=params, timeout=10)
        response.raise_for_status()
        return response.json()
    except requests.exceptions.ConnectionError:
        st.error("API inaccessible. Vérifiez que le serveur Flask est lancé.")
        return None
    except requests.exceptions.Timeout:
        st.error("L'API ne répond pas dans les délais.")
        return None
    except requests.exceptions.HTTPError:
        code = response.status_code
        if code == 404:
            st.warning("Aucune donnée trouvée pour ces critères.")
        else:
            st.error(f"Erreur API (code {code}).")
        return None
    except Exception as e:
        st.error(f"Erreur inattendue : {e}")
        return None

Utilisation dans Streamlit

python
import pandas as pd
import plotly.express as px

# Appel simple et propre
data = api_get("ventes/par-region", params={"annee": annee})
if data is not None:
    df = pd.DataFrame(data["data"])
    fig = px.bar(df, x="region", y="chiffre_affaires")
    st.plotly_chart(fig, use_container_width=True)

Le code métier (graphiques, affichage) est séparé de la gestion d'erreurs. Si api_get retourne None, on ne fait rien — l'erreur a déjà été affichée.

st.spinner : feedback visuel pendant le chargement

Un appel HTTP prend du temps (même en local). Utilisez st.spinner pour informer l'utilisateur :

python
with st.spinner("Chargement des données..."):
    data = api_get("ventes/par-region", params={"annee": annee})

if data is not None:
    df = pd.DataFrame(data["data"])
    st.dataframe(df)

st.spinner affiche un indicateur de chargement pendant que le code dans le bloc with s'exécute. Sans lui, l'utilisateur ne sait pas si le dashboard charge ou s'il est figé.

Pourquoi la fonction api_get retourne-t-elle None plutôt que de lever une exception ?

À retenir

Points clés

  • Deux catégories d'erreurs : réseau (exceptions Python) et HTTP (codes de retour)
  • requests.get() ne lève jamais d'exception pour un code 400 ou 500
  • Toujours spécifier timeout pour éviter les blocages infinis
  • raise_for_status() convertit les erreurs HTTP en exceptions
  • st.stop() arrête l'exécution du script Streamlit
  • Pattern api_get : centralise la gestion d'erreurs, retourne None en cas de problème
  • st.spinner : feedback visuel pendant les appels réseau

Votre dashboard gère maintenant les erreurs réseau. Mais un autre problème peut survenir dans certains contextes : le CORS.