Skip to content

Capítulo 4.3: Envío de solicitudes POST/PUT/DELETE

Tiempo de estudio: 1 hora


1. Comandos activos: Del lanzamiento al desguace

Hasta ahora, nuestro Centro de Control de Misión solo solicitaba información (GET). Ahora aprenderemos a enviar comandos activos:

  • POST: "¡Lanzar un nuevo satélite a órbita!"
  • PUT: "¡Realizar una modernización completa de los sistemas en la EEI!"
  • DELETE: "¡Retirar de órbita la antigua nave Debris-123!"

Para ello, utilizaremos fetch, pero con parámetros adicionales que describen nuestro comando.

💡 Analogía espacial:

Si GET es una escucha pasiva del éter radiofónico, entonces POST, PUT y DELETE son transmisiones de comandos activas. Para ello, no solo necesitamos especificar la "frecuencia" (URL), sino también el contenido del comando (cuerpo de la solicitud) y el protocolo de comunicación (encabezados).


2. Envío de solicitud POST: Lanzamiento de una nueva nave

Para crear un nuevo recurso, enviamos una solicitud POST. Lo más importante aquí es pasar el cuerpo (body) de la solicitud con los datos del nuevo objeto.

Paso 1: Añadimos el formulario de creación en index.html Lo colocaremos después del bloque "Solicitud por ID".

<!-- index.html -->
<hr>
<h2>Lanzar una nueva nave</h2>
<form id="create-ship-form">
    <input type="text" id="create-name" placeholder="Nombre" required><br>
    <input type="text" id="create-type" placeholder="Tipo" required><br>
    <input type="number" id="create-year" placeholder="Año de lanzamiento" required><br>
    <input type="text" id="create-status" placeholder="Estado" required><br>
    <button type="submit">Lanzar</button>
</form>
<div id="create-status-message"></div>

Paso 2: Añadimos la lógica en app.js

// app.js, al final del archivo

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

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

    // 1. Recopilamos los datos del formulario en un objeto
    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 = 'Enviando comando de lanzamiento...';

        // 2. Enviamos la solicitud fetch con parámetros
        const response = await fetch(`${API_BASE_URL}/spaceships`, {
            method: 'POST', // Indicamos el método
            headers: {
                'Content-Type': 'application/json' // Le decimos al servidor que enviamos JSON
            },
            body: JSON.stringify(shipData) // Convertimos el objeto JavaScript en una cadena JSON
        });

        if (!response.ok) {
            // Si el servidor devolvió un error, intentamos leer su cuerpo
            const errorData = await response.json();
            throw new Error(errorData.detail || `Error del servidor: ${response.status}`);
        }

        const newShip = await response.json();
        createStatusMessage.textContent = `🚀 ¡Lanzamiento exitoso! La nave ha recibido el ID: ${newShip.id}`;

        createShipForm.reset(); // Limpiamos el formulario
        fetchAndDisplayFleet(); // Actualizamos la lista general de la flota

    } catch (error) {
        console.error('Error al lanzar la nave:', error);
        createStatusMessage.textContent = `🔴 Error: ${error.message}`;
    }
}

createShipForm.addEventListener('submit', createShip);
Puntos clave de fetch para POST:

  • method: 'POST': Es obligatorio especificar el método HTTP.
  • headers: { 'Content-Type': 'application/json' }: Un encabezado críticamente importante. Le informa a nuestro servidor FastAPI que el cuerpo de la solicitud contiene JSON y que debe ser parseado.
  • body: JSON.stringify(shipData): No podemos enviar un objeto JavaScript directamente. Necesita ser serializado (convertido) a una cadena JSON.

3. Envío de solicitud DELETE: Desguace de una nave

La solicitud de eliminación es más sencilla: generalmente no necesita un cuerpo, solo la URL con el ID del objeto.

Paso 1: Añadimos un botón "Eliminar" a nuestra lista de naves Modificaremos la función fetchAndDisplayFleet en app.js para que añada un botón de eliminación a cada elemento.

// app.js, dentro de la función fetchAndDisplayFleet

// ...
ships.forEach(ship => {
    const listItem = document.createElement('li');
    // Añadimos un botón con un atributo data que almacena el ID
    listItem.innerHTML = `
        <strong>${ship.name} (ID: ${ship.id})</strong><br>
        Tipo: ${ship.type} | Año: ${ship.launch_year} | Estado: ${ship.status}<br>
        <button class="delete-btn" data-ship-id="${ship.id}">Desguazar nave</button>
    `;
    fleetList.appendChild(listItem);
});
// ...

Paso 2: Añadimos un controlador para todos los botones "Eliminar" Usamos delegación de eventos: un solo controlador para toda la lista.

// app.js, al final del archivo

async function deleteShip(shipId) {
    if (!confirm(`¿Estás seguro de que quieres desguazar la nave con ID ${shipId}? Esta acción es irreversible.`)) {
        return;
    }

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

        if (!response.ok) {
            throw new Error(`No se pudo desguazar la nave. Estado: ${response.status}`);
        }

        alert(`Nave con ID ${shipId} desguazada con éxito.`);
        fetchAndDisplayFleet(); // Actualizamos la lista

    } catch (error) {
        console.error('Error al desguazar:', error);
        alert(`Error: ${error.message}`);
    }
}

// Delegación de eventos: escuchamos clics en toda la lista
fleetList.addEventListener('click', (event) => {
    // Verificamos si el clic fue en un botón con la clase 'delete-btn'
    if (event.target.classList.contains('delete-btn')) {
        const shipId = event.target.dataset.shipId; // Obtenemos el ID del atributo data
        deleteShip(shipId);
    }
});

Paso 3: Añadimos id al modelo Spaceship

Añadimos id en el modelo y la base de datos en el archivo main.py

class Spaceship(BaseModel):
    id: int
    # El resto del código del modelo...

db_spaceships = {
    1: {
        "id": 1,
        # Datos del elemento 1
    },
    2: {
        "id": 2,
        # Datos del elemento 2
    },
    3: {
        "id": 3,
        # Datos del elemento 3
    }
}
  • method: 'DELETE': Indicamos el método. El cuerpo y los encabezados no son necesarios aquí.
  • confirm(): Una sencilla ventana de confirmación integrada para evitar eliminar algo importante por error.

4. Envío de solicitud PUT (Tarea independiente)

La implementación de una solicitud PUT para actualización es muy similar a POST.

Tu misión, si decides aceptarla:

  1. Añadir un botón "Modificar" junto al botón "Eliminar" para cada nave.
  2. Al hacer clic en "Modificar", rellenar el formulario (se puede usar el mismo que para crear) con los datos actuales de la nave.
  3. Cambiar el texto del botón "Lanzar" a "Actualizar".
  4. Al enviar el formulario, enviar una solicitud PUT a /spaceships/{id} con el cuerpo completo del objeto.
  5. Después de una actualización exitosa, actualizar la lista de la flota.

Sugerencia: Necesitarás fetch con method: 'PUT', encabezados Content-Type y body con JSON.stringify(), exactamente igual que en la solicitud POST.


Cuestionario de repaso

1. ¿Qué parámetro de `fetch` se utiliza para pasar datos en el cuerpo de la solicitud?

2. El encabezado `'Content-Type': 'application/json'` le indica al servidor que...

3. ¿Qué hace la función `JSON.stringify(obj)` en JavaScript?

4. Para enviar una solicitud `DELETE` usando `fetch` es obligatorio especificar:

5. La delegación de eventos en JavaScript es cuando...


🚀 Resumen del capítulo:

¡Su Centro de Control de Misión ahora tiene un conjunto completo de comandos para gestionar la flota!

  • ✅ Ha aprendido a enviar solicitudes POST con cuerpo y encabezados para crear nuevos recursos.
  • ✅ Ha implementado solicitudes DELETE para dar de baja equipos obsoletos.
  • ✅ Se le ha asignado la tarea de implementar una solicitud PUT, consolidando sus conocimientos.

¡Control total establecido! Pero, ¿qué hacer si la comunicación se interrumpe o el servidor informa un error? En el próximo capítulo, crearemos un sistema centralizado de manejo de errores en el frontend.

📌 Verificación:

  • Asegúrese de que el formulario de creación de nuevas naves funcione y que la lista en la página se actualice después de una creación exitosa.
  • Verifique que el botón "Dar de baja equipo" funcione, solicite confirmación y elimine la nave de la lista.
  • Intente crear una nave con datos no válidos (por ejemplo, con un nombre muy corto) y observe el error que devolverá su servidor FastAPI.

⚠️ Si hay errores:

  • Error 422 del servidor: Lo más probable es que los datos que está enviando no pasen la validación de Pydantic. Verifique la consola del navegador — errorData.detail mostrará en qué campo está el problema.
  • Error 415 Unsupported Media Type: Olvidó añadir el encabezado 'Content-Type': 'application/json'.
  • Los botones de eliminación no funcionan: Verifique si la delegación de eventos funciona correctamente y si está obteniendo shipId de data-ship-id correctamente.