Métodos DELETE

Intermedio
FastAPI
FastAPI
Actualizado: 01/07/2025

¡Desbloquea el curso completo!

IA
Ejercicios
Certificado
Entrar

Estructura básica de DELETE

El método DELETE es el último de los métodos HTTP fundamentales que necesitas dominar para crear APIs REST completas. Su propósito es eliminar recursos específicos del servidor, completando así el conjunto de operaciones CRUD (Create, Read, Update, Delete).

Sintaxis del decorador DELETE

En FastAPI, utilizas el decorador @app.delete() para definir endpoints que eliminen recursos. La estructura básica sigue el mismo patrón que has visto con otros métodos HTTP:

from fastapi import FastAPI

app = FastAPI()

@app.delete("/usuarios/{usuario_id}")
def eliminar_usuario(usuario_id: int):
    # Lógica de eliminación
    pass

Ejemplo práctico con datos en memoria

Vamos a crear un ejemplo completo utilizando una lista de usuarios almacenada en memoria. Primero establecemos los datos iniciales:

from fastapi import FastAPI, HTTPException

app = FastAPI()

# Base de datos simulada en memoria
usuarios = [
    {"id": 1, "nombre": "Ana", "email": "ana@email.com"},
    {"id": 2, "nombre": "Carlos", "email": "carlos@email.com"},
    {"id": 3, "nombre": "María", "email": "maria@email.com"}
]

Ahora implementamos el endpoint de eliminación:

@app.delete("/usuarios/{usuario_id}")
def eliminar_usuario(usuario_id: int):
    # Buscar el usuario por ID
    for i, usuario in enumerate(usuarios):
        if usuario["id"] == usuario_id:
            # Eliminar el usuario de la lista
            usuario_eliminado = usuarios.pop(i)
            return {"mensaje": f"Usuario {usuario_eliminado['nombre']} eliminado correctamente"}
    
    # Si no se encuentra el usuario
    raise HTTPException(status_code=404, detail="Usuario no encontrado")

Manejo de errores en DELETE

El manejo de errores en operaciones DELETE es crucial. Los casos más comunes incluyen:

  • Recurso no encontrado: Cuando intentas eliminar algo que no existe
  • Recurso ya eliminado: Cuando el recurso fue eliminado previamente
@app.delete("/productos/{producto_id}")
def eliminar_producto(producto_id: int):
    # Lista de productos simulada
    productos = [
        {"id": 1, "nombre": "Laptop", "precio": 999.99},
        {"id": 2, "nombre": "Mouse", "precio": 25.50}
    ]
    
    # Verificar si el producto existe
    producto_encontrado = None
    indice = -1
    
    for i, producto in enumerate(productos):
        if producto["id"] == producto_id:
            producto_encontrado = producto
            indice = i
            break
    
    if producto_encontrado is None:
        raise HTTPException(
            status_code=404, 
            detail=f"Producto con ID {producto_id} no encontrado"
        )
    
    # Eliminar el producto
    productos.pop(indice)
    return {"mensaje": "Producto eliminado correctamente", "producto": producto_encontrado}

Eliminación con validaciones adicionales

En aplicaciones reales, a menudo necesitas validaciones adicionales antes de eliminar un recurso:

@app.delete("/tareas/{tarea_id}")
def eliminar_tarea(tarea_id: int):
    tareas = [
        {"id": 1, "titulo": "Estudiar FastAPI", "completada": False},
        {"id": 2, "titulo": "Hacer ejercicios", "completada": True},
        {"id": 3, "titulo": "Revisar código", "completada": False}
    ]
    
    # Buscar la tarea
    for i, tarea in enumerate(tareas):
        if tarea["id"] == tarea_id:
            # Validación: solo eliminar tareas completadas
            if not tarea["completada"]:
                raise HTTPException(
                    status_code=400, 
                    detail="No se pueden eliminar tareas incompletas"
                )
            
            # Eliminar la tarea
            tarea_eliminada = tareas.pop(i)
            return {
                "mensaje": "Tarea eliminada correctamente",
                "tarea": tarea_eliminada
            }
    
    raise HTTPException(status_code=404, detail="Tarea no encontrada")

Patrón de búsqueda y eliminación

Un patrón común en operaciones DELETE es separar la lógica de búsqueda de la eliminación para mayor claridad:

def buscar_usuario_por_id(usuario_id: int):
    """Función auxiliar para buscar un usuario"""
    for i, usuario in enumerate(usuarios):
        if usuario["id"] == usuario_id:
            return i, usuario
    return None, None

@app.delete("/usuarios/{usuario_id}")
def eliminar_usuario(usuario_id: int):
    indice, usuario = buscar_usuario_por_id(usuario_id)
    
    if usuario is None:
        raise HTTPException(status_code=404, detail="Usuario no encontrado")
    
    # Eliminar el usuario
    usuarios.pop(indice)
    return {
        "mensaje": "Usuario eliminado correctamente",
        "usuario_eliminado": usuario
    }

Esta separación de responsabilidades hace que el código sea más legible y reutilizable, especialmente cuando necesitas la misma lógica de búsqueda en otros endpoints.

¿Te está gustando esta lección?

Inicia sesión para no perder tu progreso y accede a miles de tutoriales, ejercicios prácticos y nuestro asistente de IA.

Progreso guardado
Asistente IA
Ejercicios
Iniciar sesión gratis

Más de 25.000 desarrolladores ya confían en CertiDevs

Respuestas apropiadas para eliminación

Cuando implementas operaciones DELETE, es fundamental devolver códigos de estado HTTP apropiados que comuniquen claramente el resultado de la operación. FastAPI te permite especificar estos códigos de manera explícita para crear APIs más profesionales y predecibles.

Código 204 - No Content

El código 204 No Content es la respuesta estándar para eliminaciones exitosas cuando no necesitas devolver información adicional. Indica que la operación se completó correctamente pero no hay contenido que mostrar:

from fastapi import FastAPI, HTTPException, status
from fastapi.responses import Response

app = FastAPI()

usuarios = [
    {"id": 1, "nombre": "Ana", "email": "ana@email.com"},
    {"id": 2, "nombre": "Carlos", "email": "carlos@email.com"}
]

@app.delete("/usuarios/{usuario_id}", status_code=status.HTTP_204_NO_CONTENT)
def eliminar_usuario(usuario_id: int):
    for i, usuario in enumerate(usuarios):
        if usuario["id"] == usuario_id:
            usuarios.pop(i)
            return Response(status_code=status.HTTP_204_NO_CONTENT)
    
    raise HTTPException(status_code=404, detail="Usuario no encontrado")

Código 200 - OK con información

Cuando necesitas confirmar la eliminación devolviendo detalles del recurso eliminado, utiliza el código 200. Esta aproximación es útil para auditoría o confirmación visual:

@app.delete("/productos/{producto_id}")
def eliminar_producto(producto_id: int):
    productos = [
        {"id": 1, "nombre": "Laptop", "precio": 999.99, "stock": 5},
        {"id": 2, "nombre": "Mouse", "precio": 25.50, "stock": 10}
    ]
    
    for i, producto in enumerate(productos):
        if producto["id"] == producto_id:
            producto_eliminado = productos.pop(i)
            return {
                "mensaje": "Producto eliminado correctamente",
                "producto": producto_eliminado,
                "timestamp": "2024-01-15T10:30:00Z"
            }
    
    raise HTTPException(status_code=404, detail="Producto no encontrado")

Respuestas de error específicas

Las respuestas de error en DELETE deben ser descriptivas y ayudar al cliente a entender qué ocurrió:

@app.delete("/pedidos/{pedido_id}")
def eliminar_pedido(pedido_id: int):
    pedidos = [
        {"id": 1, "cliente": "Ana", "estado": "pendiente", "total": 150.00},
        {"id": 2, "cliente": "Carlos", "estado": "enviado", "total": 75.50}
    ]
    
    for i, pedido in enumerate(pedidos):
        if pedido["id"] == pedido_id:
            # Validar si se puede eliminar
            if pedido["estado"] == "enviado":
                raise HTTPException(
                    status_code=status.HTTP_409_CONFLICT,
                    detail={
                        "error": "Conflicto de estado",
                        "mensaje": "No se pueden eliminar pedidos ya enviados",
                        "pedido_id": pedido_id,
                        "estado_actual": pedido["estado"]
                    }
                )
            
            pedidos.pop(i)
            return Response(status_code=status.HTTP_204_NO_CONTENT)
    
    raise HTTPException(
        status_code=status.HTTP_404_NOT_FOUND,
        detail={
            "error": "Recurso no encontrado",
            "mensaje": f"El pedido con ID {pedido_id} no existe",
            "pedido_id": pedido_id
        }
    )

Respuestas consistentes con modelos Pydantic

Para mantener consistencia en las respuestas, puedes definir modelos Pydantic específicos para las respuestas de eliminación:

from pydantic import BaseModel
from typing import Optional

class RespuestaEliminacion(BaseModel):
    mensaje: str
    recurso_eliminado: Optional[dict] = None
    timestamp: str

class ErrorEliminacion(BaseModel):
    error: str
    mensaje: str
    recurso_id: int

@app.delete("/comentarios/{comentario_id}", response_model=RespuestaEliminacion)
def eliminar_comentario(comentario_id: int):
    comentarios = [
        {"id": 1, "texto": "Excelente artículo", "autor": "Ana"},
        {"id": 2, "texto": "Muy útil", "autor": "Carlos"}
    ]
    
    for i, comentario in enumerate(comentarios):
        if comentario["id"] == comentario_id:
            comentario_eliminado = comentarios.pop(i)
            return RespuestaEliminacion(
                mensaje="Comentario eliminado correctamente",
                recurso_eliminado=comentario_eliminado,
                timestamp="2024-01-15T10:30:00Z"
            )
    
    raise HTTPException(
        status_code=404,
        detail=ErrorEliminacion(
            error="Recurso no encontrado",
            mensaje="El comentario especificado no existe",
            recurso_id=comentario_id
        ).dict()
    )

Eliminación idempotente

Las operaciones DELETE deben ser idempotentes, es decir, ejecutar la misma eliminación múltiples veces debe producir el mismo resultado. Esto significa que intentar eliminar un recurso ya eliminado no debe generar un error:

@app.delete("/archivos/{archivo_id}")
def eliminar_archivo(archivo_id: int):
    archivos = [
        {"id": 1, "nombre": "documento.pdf", "eliminado": False},
        {"id": 2, "nombre": "imagen.jpg", "eliminado": True}  # Ya eliminado
    ]
    
    for archivo in archivos:
        if archivo["id"] == archivo_id:
            if archivo["eliminado"]:
                # Ya estaba eliminado - respuesta idempotente
                return Response(status_code=status.HTTP_204_NO_CONTENT)
            else:
                # Marcar como eliminado
                archivo["eliminado"] = True
                return Response(status_code=status.HTTP_204_NO_CONTENT)
    
    # Archivo nunca existió
    raise HTTPException(status_code=404, detail="Archivo no encontrado")

Respuestas con información de contexto

En algunos casos, es útil proporcionar información adicional sobre el impacto de la eliminación:

@app.delete("/categorias/{categoria_id}")
def eliminar_categoria(categoria_id: int):
    categorias = [
        {"id": 1, "nombre": "Electrónicos", "productos_count": 15},
        {"id": 2, "nombre": "Ropa", "productos_count": 0}
    ]
    
    for i, categoria in enumerate(categorias):
        if categoria["id"] == categoria_id:
            if categoria["productos_count"] > 0:
                raise HTTPException(
                    status_code=status.HTTP_409_CONFLICT,
                    detail={
                        "error": "Eliminación no permitida",
                        "mensaje": "No se puede eliminar una categoría con productos asociados",
                        "productos_asociados": categoria["productos_count"]
                    }
                )
            
            categoria_eliminada = categorias.pop(i)
            return {
                "mensaje": "Categoría eliminada correctamente",
                "categoria": categoria_eliminada,
                "impacto": "Sin productos afectados"
            }
    
    raise HTTPException(status_code=404, detail="Categoría no encontrada")

La elección del tipo de respuesta depende de las necesidades específicas de tu API y las expectativas de los clientes que la consumen. Lo importante es mantener consistencia en toda tu aplicación y documentar claramente el comportamiento esperado.

Aprendizajes de esta lección

  • Comprender la función y sintaxis del método DELETE en FastAPI.
  • Implementar endpoints para eliminar recursos con manejo adecuado de errores.
  • Aplicar validaciones adicionales antes de eliminar recursos.
  • Conocer y utilizar códigos de estado HTTP apropiados para respuestas de eliminación.
  • Diseñar respuestas consistentes y idempotentes para operaciones DELETE.

Completa FastAPI y certifícate

Únete a nuestra plataforma y accede a miles de tutoriales, ejercicios prácticos, proyectos reales y nuestro asistente de IA personalizado para acelerar tu aprendizaje.

Asistente IA

Resuelve dudas al instante

Ejercicios

Practica con proyectos reales

Certificados

Valida tus conocimientos

Más de 25.000 desarrolladores ya se han certificado con CertiDevs

⭐⭐⭐⭐⭐
4.9/5 valoración