File size: 4,636 Bytes
e410613
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# 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