Skip to content

Chapitre 4.4 : Gestion des erreurs

Temps d'étude : 45 minutes


1. Gestion des erreurs : protocoles d'urgence du MCC

Dans l'espace, tout peut mal tourner : une éruption solaire peut interrompre les communications, l'ordinateur de bord du vaisseau peut tomber en panne, et une commande venant de la Terre peut contenir des coordonnées incorrectes.

La gestion des erreurs sur le frontend est l'équivalent des protocoles d'urgence de votre MCC. Ils doivent :

  • 🚨 Empêcher l'interface entière de "planter" à cause d'une seule commande défectueuse.
  • 📡 Informer clairement l'opérateur (utilisateur) de ce qui n'a pas fonctionné.
  • 🔧 Proposer des actions ultérieures possibles.

💡 Analogie spatiale :

Si un signal 500 Internal Server Error est reçu du vaisseau, l'écran du MCC ne doit pas afficher "Erreur JavaScript critique à la ligne 57". Au lieu de cela, il devrait y avoir : "🚨 Défaillance à bord du vaisseau ! Les ingénieurs ont déjà été notifiés. Veuillez réessayer la commande ultérieurement."


2. Types d'"anomalies spatiales"

Sur le frontend, nous rencontrons trois types principaux d'erreurs lors de l'interaction avec une API :

  1. Erreurs réseau : La connexion au serveur n'a pas été établie. L'antenne ne fonctionne pas, le câble est coupé. fetch "tombera" dans le bloc .catch().
  2. Erreurs client (4xx) : La commande venant de la Terre était incorrecte. ID invalide, erreur de validation. Le serveur répond, mais avec un statut 4xx.
  3. Erreurs serveur (5xx) : Défaillance sur le vaisseau lui-même. Problème dans le code de l'API. Le serveur répond, mais avec un statut 500+.

Nous avons déjà commencé à les gérer avec try...catch et la vérification de response.ok. Faisons maintenant cela de manière centralisée.


3. Fonction de gestion centralisée

Répéter le même code try...catch dans chaque fonction est une mauvaise pratique. Créons un "wrapper" universel pour nos requêtes fetch.

Étape 1 : Créer api.js Créez un nouveau fichier api.js à côté de app.js. Nous y déplacerons toute la logique d'interaction avec l'API.

// api.js

const API_BASE_URL = 'http://127.0.0.1:8000';

/**
 * Fonction universelle pour exécuter des requêtes vers l'API.
 * Gère les erreurs et retourne du JSON.
 * @param {string} endpoint - Point d'accès de l'API, par exemple, '/spaceships'
 * @param {object} options - Paramètres pour fetch (method, headers, body)
 */
async function apiRequest(endpoint, options = {}) {
    const url = `${API_BASE_URL}${endpoint}`;

    try {
        const response = await fetch(url, options);

        // Si la réponse n'est pas du tout du JSON, nous levons immédiatement une erreur
        const contentType = response.headers.get('content-type');
        if (!contentType || !contentType.includes('application/json')) {
            // Exception pour une requête DELETE réussie qui n'a pas de corps
            if (response.status === 204) return null;

            throw new TypeError(`Réponse non-JSON reçue du serveur : ${response.statusText}`);
        }

        const data = await response.json();

        if (!response.ok) {
            // Si le serveur a renvoyé du JSON avec une erreur (par exemple, detail de FastAPI)
            const errorMessage = data.detail || `Erreur HTTP ! Statut : ${response.status}`;
            throw new Error(errorMessage);
        }

        return data;

    } catch (error) {
        console.error(`Erreur de requête API vers ${endpoint} :`, error);
        // Nous "relançons" l'erreur pour qu'elle puisse être interceptée dans l'UI
        throw error;
    }
}

Étape 2 : Inclure api.js dans index.html Il est important de l'inclure AVANT app.js, car app.js utilisera ses fonctions.

<!-- index.html -->
<body>
    <!-- ... -->
    <script src="api.js"></script>
    <script src="app.js"></script>
</body>

Étape 3 : Refactoriser app.js Nous allons maintenant réécrire nos fonctions en utilisant le nouveau apiRequest.

// app.js

// const API_BASE_URL = ...; // Cette ligne peut être supprimée, elle est maintenant dans api.js

// ...

async function fetchAndDisplayFleet() {
    try {
        fleetList.innerHTML = '<li>Chargement de la télémétrie...</li>';
        const ships = await apiRequest('/spaceships'); // <-- Nous utilisons notre wrapper !

        fleetList.innerHTML = '';
        if (ships.length === 0) {
            fleetList.innerHTML = '<li>Aucun appareil n\'est enregistré dans le registre.</li>';
            return;
        }

        ships.forEach(ship => { /* ... le reste du code d'affichage ... */ });
    } catch (error) {
        fleetList.innerHTML = `<li>🔴 Erreur de chargement de la flotte : ${error.message}</li>`;
    }
}

async function createShip(event) {
    event.preventDefault();
    const shipData = { /* ... collecte des données du formulaire ... */ };

    try {
        createStatusMessage.textContent = 'Envoi de la commande de lancement...';
        const options = {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(shipData)
        };
        const newShip = await apiRequest('/spaceships', options); // <-- Nous utilisons notre wrapper !

        createStatusMessage.textContent = `🚀 Lancement réussi ! L'appareil a l'ID : ${newShip.id}`;
        createShipForm.reset();
        fetchAndDisplayFleet();
    } catch (error) {
        createStatusMessage.textContent = `🔴 Erreur : ${error.message}`;
    }
}

// Réécrivez les autres fonctions (fetchShipById, deleteShip) de la même manière !
Désormais, toute la logique de gestion des erreurs réseau, de vérification de response.ok et d'analyse du JSON se trouve au même endroit, et le code dans app.js est devenu beaucoup plus propre et lisible.


4. Affichage des erreurs à l'utilisateur

Une bonne interface ne doit pas se contenter d'écrire l'erreur dans la console, mais la montrer à l'utilisateur sous une forme compréhensible.

Exemple : Amélioration de createShip Notre code le fait déjà : createStatusMessage.textContent = .... Mais on peut faire encore mieux en créant une fonction universelle pour afficher les notifications.

Ajouter à app.js :

// app.js
function showNotification(message, isError = false) {
    const notificationArea = document.getElementById('create-status-message'); // ou un autre élément
    notificationArea.textContent = message;
    notificationArea.style.color = isError ? 'red' : 'green';
}

// Utilisation dans createShip :
async function createShip(event) {
    // ...
    try {
        // ...
        const newShip = await apiRequest('/spaceships', options);
        showNotification(`🚀 Lancement réussi ! ID : ${newShip.id}`);
        // ...
    } catch (error) {
        showNotification(`🔴 Erreur : ${error.message}`, true);
    }
}
Nous avons maintenant un mécanisme unifié pour afficher à la fois les messages de succès et les erreurs.


Quiz de consolidation

1. Le bloc `.catch()` dans une promesse `fetch` se déclenchera si...

2. Pourquoi est-il nécessaire d'avoir une fonction de gestion centralisée pour les requêtes API ?

3. `response.headers.get('content-type')` est utilisé pour...

4. `throw new Error(...)` à l'intérieur de `try...catch` ou `.then()` est utilisé pour...

5. Pourquoi est-il important d'afficher les erreurs à l'utilisateur, et pas seulement dans la console ?


🚀 Résumé du chapitre :

Vous avez renforcé votre MCC en créant des protocoles d'urgence fiables.

  • 🛡️ Vous comprenez la différence entre les erreurs réseau, client et serveur.
  • ⚙️ Vous avez créé une fonction apiRequest centralisée pour gérer toutes les requêtes, évitant ainsi la duplication de code.
  • 📡 Votre interface est désormais capable d'informer correctement l'utilisateur des erreurs, la rendant plus conviviale et fiable. Boucliers d'urgence levés ! Mais qu'est-ce qui est mieux : les chaînes .then() ou le async/await moderne ? Dans le chapitre suivant, nous analyserons les deux approches et comprendrons quand utiliser laquelle.

📌 Vérification :

  • Vérifiez que votre code dans app.js est correctement refactorisé et utilise la nouvelle fonction apiRequest.
  • Essayez d'arrêter le serveur FastAPI et de cliquer sur le bouton "Demander des données". Vous devriez voir une erreur de connexion sur la page.
  • Essayez de créer un vaisseau avec des données non valides. Vous devriez voir un message d'erreur de validation provenant de FastAPI.

⚠️ En cas d'erreurs :

  • apiRequest is not defined : Assurez-vous d'avoir connecté api.js dans index.html avant app.js.
  • Vérifiez la console du navigateur pour d'autres erreurs de syntaxe en JavaScript.