10-DELETE de Película

 

DELETE de Película (CRUD Completo)

📌 Introducción al Método DELETE

En este tutorial cerraremos el ciclo CRUD (Create, Read, Update, Delete) implementando el método DELETE para eliminar registros de películas. Ya hemos visto cómo:

  • Obtener todos los registros (GET)

  • Obtener un registro específico por ID (GET)

  • Crear nuevos registros (POST)

  • Actualizar registros existentes (PUT)

Ahora implementaremos la funcionalidad para eliminar películas.

🚀 Paso 1: Configurar el Endpoint DELETE

Vamos a happy.php (o tu archivo principal de rutas) y agregamos una nueva ruta para DELETE:

php
// Copiamos la estructura de otros métodos HTTP
$app->delete('/movies/{id}', function ($request, $response, $args) {
    $id = $args['id'];
    
    // Llamamos al controlador para eliminar
    $movieController = new MovieController();
    return $movieController->delete($id, $response);
});

🛠️ Paso 2: Crear el Método DELETE en el Controller

En MovieController.php, creamos el método delete:

php
public function delete($id, $response)
{
    try {
        // 1. Validar que el ID sea numérico
        if (!is_numeric($id) || $id <= 0) {
            $errorResponse = [
                'status' => 'error',
                'message' => 'ID inválido'
            ];
            return $response->withJson($errorResponse, 400);
        }

        // 2. Obtener la película existente
        $movieModel = new Movie();
        $existingMovie = $movieModel->find($id);
        
        if (!$existingMovie) {
            // Si no existe, retornar 404
            $errorResponse = [
                'status' => 'error',
                'message' => 'Película no encontrada'
            ];
            return $response->withJson($errorResponse, 404);
        }

        // 3. Eliminar la película
        $deleted = $movieModel->destroy($id);
        
        if ($deleted) {
            // Retornar 204 No Content (éxito sin contenido)
            return $response->withStatus(204);
        } else {
            // Error en la eliminación
            $errorResponse = [
                'status' => 'error',
                'message' => 'Error al eliminar la película'
            ];
            return $response->withJson($errorResponse, 500);
        }
        
    } catch (Exception $e) {
        $errorResponse = [
            'status' => 'error',
            'message' => 'Error interno del servidor: ' . $e->getMessage()
        ];
        return $response->withJson($errorResponse, 500);
    }
}

📝 Paso 3: Implementar el Método destroy en el Modelo

En tu modelo Movie.php, agrega el método destroy:

php
public function destroy($id)
{
    try {
        // Preparar la consulta DELETE
        $sql = "DELETE FROM movies WHERE id = :id";
        $stmt = $this->db->prepare($sql);
        
        // Vincular parámetros
        $stmt->bindParam(':id', $id, PDO::PARAM_INT);
        
        // Ejecutar la consulta
        return $stmt->execute();
        
    } catch (PDOException $e) {
        // Log del error (en producción usarías un logger)
        error_log("Error al eliminar película: " . $e->getMessage());
        return false;
    }
}

🔍 Paso 4: Probar el Endpoint DELETE

Usando Postman:

  1. Configuración de la petición:

    • Método: DELETE

    • URL: http://tu-dominio.com/movies/1

    • Headers: Content-Type: application/json

  2. Ejemplos de respuesta:

    Éxito (204 No Content):

    text
    Status: 204 No Content
    Body: (vacío)

    Película no encontrada (404):

    json
    {
      "status": "error",
      "message": "Película no encontrada"
    }

    ID inválido (400):

    json
    {
      "status": "error",
      "message": "ID inválido"
    }

🎯 Paso 5: Consideraciones de Seguridad

5.1 Validación de Autorización (si es necesario)

php
// Verificar si el usuario tiene permisos para eliminar
if (!$this->auth->canDelete()) {
    $errorResponse = [
        'status' => 'error',
        'message' => 'No autorizado para eliminar recursos'
    ];
    return $response->withJson($errorResponse, 403);
}

5.2 Eliminación Lógica vs Física

Considera implementar "soft delete" (eliminación lógica) en lugar de borrado físico:

php
// En lugar de DELETE, hacer UPDATE con un campo 'deleted_at'
public function softDestroy($id)
{
    $sql = "UPDATE movies SET deleted_at = NOW(), active = 0 WHERE id = :id";
    $stmt = $this->db->prepare($sql);
    $stmt->bindParam(':id', $id, PDO::PARAM_INT);
    return $stmt->execute();
}

📋 Paso 6: Pruebas Unitarias (Ejemplo)

php
class MovieDeleteTest extends TestCase
{
    public function testDeleteMovieSuccess()
    {
        // Crear una película de prueba
        $movieId = $this->createTestMovie();
        
        // Eliminar la película
        $response = $this->delete("/movies/{$movieId}");
        
        // Verificar respuesta
        $this->assertEquals(204, $response->getStatusCode());
        
        // Verificar que ya no existe
        $response = $this->get("/movies/{$movieId}");
        $this->assertEquals(404, $response->getStatusCode());
    }
    
    public function testDeleteNonExistentMovie()
    {
        $response = $this->delete("/movies/999999");
        $this->assertEquals(404, $response->getStatusCode());
    }
}

🔄 Paso 7: Integración con Frontend

Ejemplo con JavaScript (Fetch API):

javascript
async function deleteMovie(movieId) {
    if (!confirm('¿Estás seguro de eliminar esta película?')) {
        return;
    }
    
    try {
        const response = await fetch(`/api/movies/${movieId}`, {
            method: 'DELETE',
            headers: {
                'Authorization': `Bearer ${localStorage.getItem('token')}`
            }
        });
        
        if (response.status === 204) {
            // Eliminar el elemento del DOM
            document.getElementById(`movie-${movieId}`).remove();
            showNotification('Película eliminada correctamente', 'success');
        } else if (response.status === 404) {
            showNotification('La película no existe', 'error');
        } else {
            const error = await response.json();
            showNotification(error.message, 'error');
        }
    } catch (error) {
        showNotification('Error de conexión', 'error');
    }
}

📊 Resumen del CRUD Completo

MétodoEndpointDescripciónCódigos HTTP comunes
GET/moviesObtener todas las películas200, 500
GET/movies/{id}Obtener una película específica200, 404, 400
POST/moviesCrear nueva película201, 400, 422
PUT/movies/{id}Actualizar película existente200, 404, 400
DELETE/movies/{id}Eliminar película204, 404, 400

🎉 Conclusión

¡Felicidades! Has completado la implementación del CRUD completo:

✅ Create - POST
✅ Read - GET (todos y por ID)
✅ Update - PUT
✅ Delete - DELETE

Con esto has construido una API RESTful completa para gestionar películas. En la siguiente parte del curso integraremos un frontend que consumirá esta API, permitiéndonos decir adiós a Postman y probar todo desde una interfaz gráfica.

📚 Buenas Prácticas Adicionales

  1. Logging: Implementa un sistema de logging para registrar eliminaciones

  2. Backup: Considera crear backups de datos importantes antes de eliminaciones

  3. Rate Limiting: Limita la cantidad de peticiones DELETE por usuario

  4. CORS: Configura adecuadamente los encabezados CORS

  5. Documentación: Documenta tu API con OpenAPI/Swagger

¡Nos vemos en la siguiente parte donde integraremos el frontend

Comentarios

Entradas más populares de este blog

Axios para Principiantes - Guía Paso a Paso

15-Tutorial: Crear Película en React con useState

Tutorial de React para Principiantes