Skip to content

Capítulo 3.4: Operaciones CRUD para naves espaciales

Tiempo de estudio: 1 hora


1. CRUD: Ciclo completo de gestión de misiones espaciales

Hasta ahora, solo hemos leído datos (Read). Pero un verdadero Centro de Control de Misiones debe ser capaz de todo:

  • Create (Crear): Lanzar un nuevo satélite a órbita.
  • Read (Leer): Solicitar el estado de una nave existente.
  • Update (Actualizar): Corregir la órbita o actualizar el software.
  • Delete (Eliminar): Retirar un satélite antiguo de órbita.

Estas cuatro operaciones — CRUD — constituyen la base de la mayoría de las API. En este capítulo, implementaremos el ciclo completo para gestionar nuestra flota.


2. Create: Lanzamiento de una nueva nave (POST)

Para crear una nueva nave espacial, utilizaremos el método POST. Los datos para la nueva nave se enviarán en el cuerpo de la solicitud en formato JSON.

Paso 1: Creamos un nuevo modelo Pydantic para los datos entrantes ¿Por qué se necesita un nuevo modelo? Porque al crear una nave, no conocemos su id — este debe ser asignado por el servidor.

Añada este modelo a main.py:

# main.py
from pydantic import BaseModel, Field

class SpaceshipCreate(BaseModel):
    """Modelo para crear una nueva nave (sin ID)."""
    name: str = Field(..., min_length=3, max_length=50)
    type: str
    launch_year: int = Field(..., gt=1950)
    status: str
Este modelo es casi idéntico a Spaceship, pero se utilizará para la validación de datos entrantes.

Paso 2: Implementamos el endpoint POST /spaceships

# main.py
import random # Añada esta importación al principio del archivo

# ... resto del código ...

@app.post("/spaceships", response_model=Spaceship, status_code=201)
def create_spaceship(ship: SpaceshipCreate):
    """
    Añade una nueva nave espacial al registro.
    """
    # Generamos un nuevo ID único para la nave
    new_id = max(db_spaceships.keys() or [0]) + 1

    # Creamos un objeto de nave que corresponde al modelo completo Spaceship
    new_ship = Spaceship(id=new_id, **ship.dict())

    # Guardamos en nuestra "base de datos"
    db_spaceships[new_id] = new_ship.dict()

    return new_ship
Desglose:

  • @app.post(...): Usamos el decorador para solicitudes POST.
  • status_code=201: Indicamos que, en caso de creación exitosa, se debe devolver el estado 201 Created.
  • ship: SpaceshipCreate: ¡Aquí está la magia! FastAPI tomará automáticamente el cuerpo de la solicitud (JSON), lo validará según el modelo SpaceshipCreate y lo pasará a la función como un objeto ship.
  • new_id = ...: Lógica simple para generar un nuevo ID.
  • **ship.dict(): "Desempaquetamos" los datos del modelo ship recibido en nuestro modelo completo.
  • response_model=Spaceship: La respuesta corresponderá al modelo completo, incluyendo el id.

3. Update: Corrección de rumbo (PUT)

Para la actualización completa de un recurso existente, se utiliza el método PUT.

Implementamos el endpoint PUT /spaceships/{ship_id}:

# main.py
from fastapi import FastAPI, HTTPException # Actualice la importación

# ... resto del código ...

@app.put("/spaceships/{ship_id}", response_model=Spaceship)
def update_spaceship(ship_id: int, ship_update: SpaceshipCreate):
    """
    Actualiza completamente los datos de una nave espacial.
    """
    if ship_id not in db_spaceships:
        raise HTTPException(status_code=404, detail="Nave espacial no encontrada")

    updated_ship = Spaceship(id=ship_id, **ship_update.dict())
    db_spaceships[ship_id] = updated_ship.dict()

    return updated_ship

  • ship_update: SpaceshipCreate: Volvemos a usar nuestro modelo para la validación de los datos entrantes.
  • HTTPException: Si no se encuentra una nave con ese id, "lanzamos" una excepción estándar de FastAPI que se convertirá en una bonita respuesta JSON con el código 404.

4. Delete: Salida de órbita (DELETE)

Para eliminar un recurso, se utiliza el método DELETE. Normalmente, este tipo de endpoint no devuelve un cuerpo de respuesta.

Implementamos el endpoint DELETE /spaceships/{ship_id}:

# main.py
from fastapi import FastAPI, HTTPException, Response, status # Actualice la importación

# ... resto del código ...

@app.delete("/spaceships/{ship_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_spaceship(ship_id: int):
    """
    Elimina una nave espacial del registro.
    """
    if ship_id not in db_spaceships:
        raise HTTPException(status_code=404, detail="Nave espacial no encontrada")

    del db_spaceships[ship_id]

    # Devolvemos una respuesta vacía con el estado 204
    return Response(status_code=status.HTTP_204_NO_CONTENT)

  • status_code=status.HTTP_204_NO_CONTENT: Indicamos explícitamente el estado 204 No Content.
  • del db_spaceships[ship_id]: Eliminamos la entrada de nuestro diccionario.
  • return Response(...): Devolvemos una respuesta vacía, ya que el cliente no necesita datos sobre el objeto eliminado.

5. Pruebas del ciclo completo en /docs

Su uvicorn debería haberse recargado.

  1. Abra http://127.0.0.1:8000/docs. ¡Ahora tiene un conjunto completo de operaciones CRUD!
  2. POST: Expanda el endpoint POST /spaceships, haga clic en "Try it out", rellene el cuerpo JSON (por ejemplo, cree "James Webb Telescope") y haga clic en "Execute". Debería recibir una respuesta 201 con los datos del nuevo telescopio.
  3. GET: Ahora ejecute GET /spaceships. Su nuevo telescopio debería aparecer en la lista.
  4. PUT: Use el ID del nuevo telescopio para actualizar sus datos a través de PUT /spaceships/{ship_id}. Por ejemplo, cambie su estado.
  5. DELETE: Use el mismo ID para eliminar el telescopio a través de DELETE /spaceships/{ship_id}. Debería recibir una respuesta vacía con el estado 204.
  6. Verificación: Ejecute GET /spaceships de nuevo para asegurarse de que el telescopio ha sido eliminado de la lista.

Cuestionario de repaso

1. ¿Qué método HTTP se utiliza para crear un nuevo recurso?

2. Código de estado estándar de éxito para la operación `DELETE`:

3. ¿Cómo obtiene FastAPI los datos del cuerpo de una solicitud POST?

4. `raise HTTPException(status_code=404)` se utiliza para:

5. ¿Por qué creamos un modelo `SpaceshipCreate` separado para la creación de recursos (`POST`)?


🚀 Resumen del capítulo:

¡Has implementado un ciclo CRUD completo y has transformado tu API de un simple "tablero informativo" en un completo Centro de Control de Flota!

  • Create: POST /spaceships para lanzar nuevas naves.
  • Read: GET /spaceships y GET /spaceships/{id} para obtener datos.
  • Update: PUT /spaceships/{id} para actualizar misiones.
  • Delete: DELETE /spaceships/{id} para dar de baja naves.

¡Tu flota bajo control total! En el siguiente capítulo veremos cómo FastAPI creó automáticamente para nosotros una detallada "guía de operación": la documentación interactiva de Swagger.

📌 Verificación:

  • Todos los 5 endpoints (GET (2), POST, PUT, DELETE) son visibles y funcionan en /docs.
  • Puedes crear, leer, actualizar y eliminar un recurso con éxito.
  • Al solicitar un ID inexistente, se devuelve un error 404.

⚠️ Si hay errores:

  • NameError: Verifica que has importado HTTPException, Response, status.
  • KeyError: Probablemente estás intentando acceder a un ID que ya ha sido eliminado.
  • Funcionamiento incorrecto de PUT o POST: Asegúrate de que estás utilizando el modelo Pydantic correcto en el argumento de la función (SpaceshipCreate). ```