Skip to content

Chapitre 4.3 : Envoi de requêtes POST/PUT/DELETE

Temps d'étude : 1 heure


1. Commandes actives : Du lancement au déclassement

Jusqu'à présent, notre centre de contrôle (MCC) ne faisait que demander des informations (GET). Nous allons maintenant apprendre à envoyer des commandes actives :

  • POST : "Lancer un nouveau satellite en orbite !"
  • PUT : "Effectuer une mise à niveau complète des systèmes de l'ISS !"
  • DELETE : "Désorbiter l'ancien appareil Debris-123 !"

Pour ce faire, nous utiliserons fetch, mais avec des paramètres supplémentaires qui décrivent notre commande.

💡 Analogie spatiale :

Si GET est une écoute passive de la radio, POST, PUT et DELETE sont une transmission active de commandes. Pour cela, il ne suffit pas d'indiquer la "fréquence" (URL), mais aussi le contenu de la commande (corps de la requête) et le protocole de communication (en-têtes).


2. Envoi d'une requête POST : Lancement d'un nouveau vaisseau

Pour créer une nouvelle ressource, nous envoyons une requête POST. Le plus important ici est de transmettre le corps (body) de la requête avec les données du nouvel objet.

Étape 1 : Ajout du formulaire de création dans index.html Plaçons-le après le bloc "Requête par ID".

<!-- index.html -->
<hr>
<h2>Lancer un nouvel appareil</h2>
<form id="create-ship-form">
    <input type="text" id="create-name" placeholder="Nom" required><br>
    <input type="text" id="create-type" placeholder="Type" required><br>
    <input type="number" id="create-year" placeholder="Année de lancement" required><br>
    <input type="text" id="create-status" placeholder="Statut" required><br>
    <button type="submit">Lancer</button>
</form>
<div id="create-status-message"></div>

Étape 2 : Ajout de la logique dans app.js

// app.js, à la fin du fichier

const createShipForm = document.getElementById('create-ship-form');
const createStatusMessage = document.getElementById('create-status-message');

async function createShip(event) {
    event.preventDefault();

    // 1. Rassemble les données du formulaire dans un objet
    const shipData = {
        name: document.getElementById('create-name').value,
        type: document.getElementById('create-type').value,
        launch_year: parseInt(document.getElementById('create-year').value),
        status: document.getElementById('create-status').value
    };

    try {
        createStatusMessage.textContent = 'Envoi de la commande de lancement...';

        // 2. Envoie la requête fetch avec les paramètres
        const response = await fetch(`${API_BASE_URL}/spaceships`, {
            method: 'POST', // Indique la méthode
            headers: {
                'Content-Type': 'application/json' // Indique au serveur que nous envoyons du JSON
            },
            body: JSON.stringify(shipData) // Convertit l'objet JavaScript en chaîne JSON
        });

        if (!response.ok) {
            // Si le serveur a renvoyé une erreur, essaie de lire son corps
            const errorData = await response.json();
            throw new Error(errorData.detail || `Erreur serveur : ${response.status}`);
        }

        const newShip = await response.json();
        createStatusMessage.textContent = `🚀 Lancement réussi ! L'appareil a l'ID : ${newShip.id}`;

        createShipForm.reset(); // Efface le formulaire
        fetchAndDisplayFleet(); // Met à jour la liste générale de la flotte

    } catch (error) {
        console.error('Erreur lors du lancement de l\'appareil :', error);
        createStatusMessage.textContent = `🔴 Erreur : ${error.message}`;
    }
}

createShipForm.addEventListener('submit', createShip);
Points clés de fetch pour POST :

  • method: 'POST' : Il est impératif d'indiquer la méthode HTTP.
  • headers: { 'Content-Type': 'application/json' } : Cet en-tête est crucial. Il indique à notre serveur FastAPI que le corps de la requête contient du JSON et qu'il doit être analysé.
  • body: JSON.stringify(shipData) : Nous ne pouvons pas envoyer un objet JavaScript directement. Il doit être sérialisé (converti) en chaîne JSON.

3. Envoi d'une requête DELETE : Déclassement d'un appareil

La requête de suppression est plus simple : elle n'a généralement pas besoin de corps, seulement d'une URL avec l'ID de l'objet.

Étape 1 : Ajout du bouton "Supprimer" dans notre liste de vaisseaux Modifions la fonction fetchAndDisplayFleet dans app.js pour qu'elle ajoute un bouton de suppression pour chaque élément.

// app.js, à l'intérieur de la fonction fetchAndDisplayFleet

// ...
ships.forEach(ship => {
    const listItem = document.createElement('li');
    // Ajoute un bouton avec un attribut data stockant l'ID
    listItem.innerHTML = `
        <strong>${ship.name} (ID: ${ship.id})</strong><br>
        Type: ${ship.type} | Année: ${ship.launch_year} | Statut: ${ship.status}<br>
        <button class="delete-btn" data-ship-id="${ship.id}">Déclasser l'appareil</button>
    `;
    fleetList.appendChild(listItem);
});
// ...

Étape 2 : Ajout d'un gestionnaire pour tous les boutons "Supprimer" Nous utilisons la délégation d'événements - un seul gestionnaire pour toute la liste.

// app.js, à la fin du fichier

async function deleteShip(shipId) {
    if (!confirm(`Êtes-vous sûr de vouloir déclasser l'appareil avec l'ID ${shipId} ? Cette action est irréversible.`)) {
        return;
    }

    try {
        const response = await fetch(`${API_BASE_URL}/spaceships/${shipId}`, {
            method: 'DELETE' // Indique la méthode
        });

        if (!response.ok) {
            throw new Error(`Échec du déclassement de l'appareil. Statut : ${response.status}`);
        }

        alert(`L'appareil avec l'ID ${shipId} a été déclassé avec succès.`);
        fetchAndDisplayFleet(); // Met à jour la liste

    } catch (error) {
        console.error('Erreur lors du déclassement :', error);
        alert(`Erreur : ${error.message}`);
    }
}

// Délégation d'événements : écoute les clics sur toute la liste
fleetList.addEventListener('click', (event) => {
    // Vérifie si le clic a eu lieu sur un bouton avec la classe 'delete-btn'
    if (event.target.classList.contains('delete-btn')) {
        const shipId = event.target.dataset.shipId; // Récupère l'ID depuis l'attribut data
        deleteShip(shipId);
    }
});

Étape 3 : Ajout de l'id au modèle Spaceship

Ajoutez l'id aux modèles et à la base de données dans le fichier main.py.

class Spaceship(BaseModel):
    id: int
    # Reste du code du modèle...

db_spaceships = {
    1: {
        "id": 1,
        # Données de l'élément 1
    },
    2: {
        "id": 2,
        # Données de l'élément 2
    },
    3: {
        "id": 3,
        # Données de l'élément 3
    }
}
  • method: 'DELETE' : Indique la méthode. Le corps et les en-têtes ne sont pas nécessaires ici.
  • confirm() : Simple fenêtre de confirmation intégrée pour éviter de supprimer accidentellement quelque chose d'important.

4. Envoi d'une requête PUT (Tâche autonome)

L'implémentation d'une requête PUT pour la mise à jour est très similaire à POST.

Votre mission, si vous choisissez de l'accepter :

  1. Ajouter un bouton "Modifier" à côté du bouton "Supprimer" pour chaque vaisseau.
  2. Lorsque vous cliquez sur "Modifier", remplissez le formulaire (vous pouvez utiliser le même que pour la création) avec les données actuelles du vaisseau.
  3. Modifiez le texte du bouton "Lancer" en "Mettre à jour".
  4. Lors de la soumission du formulaire, envoyez une requête PUT à /spaceships/{id} avec le corps complet de l'objet.
  5. Après une mise à jour réussie, mettez à jour la liste de la flotte.

Indice : Vous aurez besoin de fetch avec method: 'PUT', les en-têtes Content-Type et body avec JSON.stringify(), exactement comme dans la requête POST.


Quiz pour la consolidation

1. Quel paramètre `fetch` est utilisé pour transmettre des données dans le corps de la requête ?

2. L'en-tête `'Content-Type': 'application/json'` indique au serveur que...

3. Que fait la fonction `JSON.stringify(obj)` en JavaScript ?

4. Pour envoyer une requête `DELETE` avec `fetch`, il faut absolument indiquer :

5. La délégation d'événements en JavaScript, c'est quand...

resultsHTML += </ul><p><b>Votre score : ${score} sur ${Object.keys(correctAnswers).length}</b></p>; resultsContainer.innerHTML = resultsHTML; resultsContainer.style.display = 'block'; }


🚀 Résumé du chapitre :

Votre Centre de Contrôle de Mission (CCM) dispose maintenant d'un ensemble complet de commandes pour gérer la flotte !

  • ✅ Vous avez appris à envoyer des requêtes POST avec un corps et des en-têtes pour créer de nouvelles ressources.
  • ✅ Vous avez implémenté des requêtes DELETE pour désactiver les appareils obsolètes.
  • ✅ Vous avez reçu la tâche d'implémenter une requête PUT, consolidant ainsi vos connaissances.

Le contrôle total est établi ! Mais que faire si la connexion est interrompue ou si le serveur signale une erreur ? Dans le prochain chapitre, nous allons créer un système centralisé de gestion des erreurs côté front-end.

📌 Vérification :

  • Assurez-vous que le formulaire de création d'un nouveau vaisseau fonctionne et qu'après une création réussie, la liste sur la page est mise à jour.
  • Vérifiez que le bouton "Désactiver l'appareil" fonctionne, demande confirmation et supprime le vaisseau de la liste.
  • Essayez de créer un vaisseau avec des données non valides (par exemple, avec un nom très court) et observez l'erreur que votre serveur FastAPI renverra.

⚠️ En cas d'erreurs :

  • Erreur 422 du serveur : Il est probable que les données que vous envoyez ne passent pas la validation Pydantic. Vérifiez la console du navigateur — errorData.detail indiquera le champ problématique.
  • Erreur 415 Unsupported Media Type : Vous avez oublié d'ajouter l'en-tête 'Content-Type': 'application/json'.
  • Les boutons de suppression ne fonctionnent pas : Vérifiez si la délégation d'événements fonctionne correctement et si vous récupérez correctement shipId à partir de data-ship-id.