# main.py from fastapi import FastAPI, HTTPException, status from pydantic import BaseModel from typing import Optional, List # --- Modelos de Datos con Pydantic --- # Pydantic se encarga de la validación y serialización de datos class Item(BaseModel): """Modelo base para un ítem. Todos los campos son requeridos.""" id: int name: str description: Optional[str] = None price: float class UpdateItem(BaseModel): """Modelo para actualizar un ítem. Todos los campos son opcionales.""" name: Optional[str] = None description: Optional[str] = None price: Optional[float] = None # --- Instancia de la Aplicación FastAPI --- app = FastAPI( title="API de Ejemplo Completa", description="Una API de ejemplo con todos los métodos HTTP para demostrar FastAPI, Docker y Hugging Face Spaces.", version="1.0.0", ) # --- "Base de Datos" en Memoria --- # Un diccionario simple para simular una base de datos. db = { 1: Item(id=1, name="Laptop", description="Un potente portátil para desarrollo", price=1200.50), 2: Item(id=2, name="Teclado Mecánico", description="Un teclado con switches Cherry MX Blue", price=150.75), } # --- Endpoints de la API --- @app.get("/", tags=["Root"]) def read_root(): """Endpoint principal de bienvenida.""" return {"message": "¡Bienvenido a la API de ejemplo con FastAPI!"} # --- Métodos para la colección de ítems --- @app.get("/items", response_model=List[Item], tags=["Items"]) def get_all_items(): """ GET: Obtiene una lista de todos los ítems en la base de datos. """ return list(db.values()) @app.post("/items", response_model=Item, status_code=status.HTTP_201_CREATED, tags=["Items"]) def create_item(item: Item): """ POST: Crea un nuevo ítem. El ID del ítem en el cuerpo de la petición debe ser único. """ if item.id in db: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=f"El ítem con ID {item.id} ya existe." ) db[item.id] = item return item # --- Métodos para un ítem específico --- @app.get("/items/{item_id}", response_model=Item, tags=["Items"]) def get_item_by_id(item_id: int): """ GET: Obtiene un ítem específico por su ID. """ if item_id not in db: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"El ítem con ID {item_id} no fue encontrado." ) return db[item_id] @app.put("/items/{item_id}", response_model=Item, tags=["Items"]) def update_item_completely(item_id: int, item: Item): """ PUT: Actualiza un ítem completamente. Reemplaza toda la información del ítem existente con la nueva. """ if item_id not in db: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"El ítem con ID {item_id} no fue encontrado." ) # El ID no debe cambiar en una operación PUT if item_id != item.id: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="El ID del ítem en la URL no coincide con el ID en el cuerpo de la petición." ) db[item_id] = item return db[item_id] @app.patch("/items/{item_id}", response_model=Item, tags=["Items"]) def update_item_partially(item_id: int, item_update: UpdateItem): """ PATCH: Actualiza un ítem parcialmente. Solo actualiza los campos proporcionados en el cuerpo de la petición. """ if item_id not in db: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"El ítem con ID {item_id} no fue encontrado." ) stored_item_data = db[item_id].dict() update_data = item_update.dict(exclude_unset=True) # Obtiene solo los campos que se enviaron updated_item_data = stored_item_data.copy() updated_item_data.update(update_data) db[item_id] = Item(**updated_item_data) return db[item_id] @app.delete("/items/{item_id}", status_code=status.HTTP_204_NO_CONTENT, tags=["Items"]) def delete_item(item_id: int): """ DELETE: Elimina un ítem por su ID. Devuelve un código 204 sin contenido si tiene éxito. """ if item_id not in db: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=f"El ítem con ID {item_id} no fue encontrado." ) del db[item_id] # No se devuelve contenido, solo el código de estado 204 return