Desarrollo de APIs con FastAPI

Si Django es una navaja suiza, FastAPI es un motor de Fórmula 1. Es moderno, usa las últimas características de Python y se encarga de que los datos que entran y salen sean siempre correctos.

1. ¿Qué es una API y por qué FastAPI?

🍰 La Metáfora del Restaurante

Imagina un restaurante. Tú eres el cliente (Frontend/App Móvil) y la cocina es el servidor (Base de datos).

  • No puedes entrar a la cocina a coger la comida.
  • Necesitas un Camarero que tome tu nota, la valide ("¿tenemos stock?") y te traiga el plato.
  • La API es el camarero.

FastAPI es especial porque valida la "nota" automáticamente. Si pides "milanesa", pero escribes números, FastAPI te detiene antes de llegar a la cocina.

2. Instalación y el servidor Uvicorn

A diferencia de Django, FastAPI no trae servidor web integrado. Necesitamos instalar uno ultrarrápido llamado Uvicorn.

Terminal
pip install fastapi uvicorn

Creamos nuestro primer archivo. Fíjate en la sintaxis moderna:

main.py
from fastapi import FastAPI

app = FastAPI()

# Decorador: Cuando alguien visite la raiz "/"...
@app.get("/")
def home():
    return {"mensaje": "¡Hola! Mi API está viva"}

Para encenderlo, usamos el comando "reload" para que se actualice si cambiamos código:

Terminal
uvicorn main:app --reload

3. Parámetros: Hablando con la API

Hay dos formas principales de enviar información en la URL. Es vital distinguirlas.

A. Path Parameters (Parte de la ruta)

Se usan para identificar recursos específicos (ej: el usuario número 5).

@app.get("/usuarios/{user_id}")
def leer_usuario(user_id: int): # <--- FastAPI convierte el texto a int automáticamente
    return {"usuario_id": user_id}

URL: /usuarios/5

B. Query Parameters (Búsqueda/Filtro)

Si declaras una variable que NO está en la ruta, FastAPI asume que es un filtro (lo que va después del `?`).

@app.get("/productos/")
def listar_productos(skip: int = 0, limit: int = 10):
    return {"mostrando_desde": skip, "hasta": limit}

URL: /productos/?skip=20&limit=50

4. Pydantic: El Portero de Discoteca (Validación)

Esta es la característica estrella. En lugar de comprobar manualmente si el usuario envió bien los datos, definimos un Modelo.

🛡 Data Validation Si definimos que el precio es un float, y el usuario envía "cinco euros", FastAPI devolverá un error 422 automáticamente explicando qué falló.
main.py
from pydantic import BaseModel
from typing import Optional

# Definimos la "forma" que deben tener los datos
class Producto(BaseModel):
    nombre: str
    precio: float
    en_oferta: bool = False # Opcional, por defecto False
    descripcion: Optional[str] = None

5. CRUD y Métodos HTTP

Vamos a usar el modelo Producto para recibir datos (POST).

main.py
@app.post("/productos/")
def crear_producto(item: Producto): 
    # Aquí `item` ya es un objeto validado.
    # Podemos acceder a item.precio, item.nombre, etc.
    
    precio_final = item.precio
    if item.en_oferta:
        precio_final = item.precio * 0.50 # 50% descuento
        
    return {"producto": item.nombre, "precio_cobrado": precio_final}

6. Documentación Automática (Swagger UI)

Lo mejor de FastAPI es que no tienes que escribir documentación. Al leer tus tipos de datos (`int`, `str`, `Producto`), genera una web interactiva.

🔮 Pruébalo ahora Si tu servidor está corriendo, entra a: http://127.0.0.1:8000/docs.
Verás un botón "Try it out" para probar tu API sin programar nada extra.

7. Concurrencia (Async / Await)

Python tradicional lee el código línea por línea y espera. Si hay una consulta lenta a la base de datos, todo el servidor se congela. FastAPI usa async.

Significa que mientras espera la base de datos, el servidor puede atender a otro usuario.

import asyncio

@app.get("/tarea-pesada")
async def leer_datos():
    # Simula una operación lenta (ej: consultar IA externa)
    await asyncio.sleep(3) 
    return {"status": "Terminado"}

8. Arquitectura Profesional (APIRouter)

No puedes poner 100 rutas en un solo archivo main.py. FastAPI usa APIRouter para dividir la aplicación en ficheros (igual que las Apps de Django).

routers/usuarios.py
from fastapi import APIRouter

router = APIRouter()

@router.get("/users/")
def get_users():
    return [{"name": "Ana"}]
main.py (Principal)
from routers import usuarios

app = FastAPI()

# Conectamos el router secundario al principal
app.include_router(usuarios.router)