FastAPI es el framework de Python más moderno y de mayor crecimiento para crear APIs REST. Combina velocidad comparable a Node.js, tipado estático con Pydantic, documentación automática Swagger y soporte nativo de asincronía. En este tutorial aprenderás a crear una API REST completa con FastAPI desde cero, paso a paso.

¿Por qué elegir FastAPI?

  • Uno de los frameworks Python más rápidos (basado en Starlette y Uvicorn)
  • Tipado estático con Pydantic: menos bugs, mejor autocompletado en el editor
  • Documentación interactiva automática (Swagger UI en /docs y ReDoc en /redoc)
  • Soporte nativo de asincronía con async/await
  • Más intuitivo que Flask para APIs, menos complejo que Django REST Framework

Instalación y primer endpoint

pip install fastapi uvicorn[standard] pydantic sqlalchemy
# main.py
from fastapi import FastAPI

app = FastAPI(title="Mi API", version="1.0.0")

@app.get("/")
def inicio():
    return {"mensaje": "Bienvenido a FastAPI!"}

@app.get("/saludo/{nombre}")
def saludar(nombre: str, mayusculas: bool = False):
    saludo = f"Hola, {nombre}!"
    return {"saludo": saludo.upper() if mayusculas else saludo}

Ejecuta con: uvicorn main:app --reload

Abre http://localhost:8000/docs para ver la documentación interactiva generada automáticamente.

Modelos con Pydantic

from pydantic import BaseModel, EmailStr, validator
from typing import Optional
from datetime import datetime

class Usuario(BaseModel):
    id: Optional[int] = None
    nombre: str
    email: EmailStr
    activo: bool = True
    creado_en: datetime = datetime.now()

    @validator("nombre")
    def nombre_no_vacio(cls, v):
        if len(v.strip()) < 2:
            raise ValueError("El nombre debe tener al menos 2 caracteres")
        return v.strip().title()

CRUD completo con base de datos

from fastapi import FastAPI, HTTPException, Depends
from sqlalchemy import create_engine, Column, Integer, String, Boolean
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, Session

DATABASE_URL = "sqlite:///./usuarios.db"
engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()

class UsuarioDB(Base):
    __tablename__ = "usuarios"
    id = Column(Integer, primary_key=True, index=True)
    nombre = Column(String(100))
    email = Column(String(200), unique=True)
    activo = Column(Boolean, default=True)

Base.metadata.create_all(bind=engine)
app = FastAPI()

def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

@app.post("/usuarios/", status_code=201)
def crear_usuario(usuario: Usuario, db: Session = Depends(get_db)):
    db_user = UsuarioDB(nombre=usuario.nombre, email=usuario.email)
    db.add(db_user)
    db.commit()
    db.refresh(db_user)
    return {"id": db_user.id, "nombre": db_user.nombre}

@app.get("/usuarios/")
def listar_usuarios(skip: int = 0, limit: int = 10, db: Session = Depends(get_db)):
    return db.query(UsuarioDB).offset(skip).limit(limit).all()

@app.get("/usuarios/{usuario_id}")
def obtener_usuario(usuario_id: int, db: Session = Depends(get_db)):
    usuario = db.query(UsuarioDB).filter(UsuarioDB.id == usuario_id).first()
    if not usuario:
        raise HTTPException(status_code=404, detail="Usuario no encontrado")
    return usuario

@app.put("/usuarios/{usuario_id}")
def actualizar_usuario(usuario_id: int, datos: Usuario, db: Session = Depends(get_db)):
    usuario = db.query(UsuarioDB).filter(UsuarioDB.id == usuario_id).first()
    if not usuario:
        raise HTTPException(status_code=404, detail="Usuario no encontrado")
    usuario.nombre = datos.nombre
    db.commit()
    return usuario

@app.delete("/usuarios/{usuario_id}", status_code=204)
def eliminar_usuario(usuario_id: int, db: Session = Depends(get_db)):
    usuario = db.query(UsuarioDB).filter(UsuarioDB.id == usuario_id).first()
    if not usuario:
        raise HTTPException(status_code=404, detail="Usuario no encontrado")
    db.delete(usuario)
    db.commit()

Middleware y CORS

from fastapi.middleware.cors import CORSMiddleware

app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://localhost:3000"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

FastAPI vs Flask vs Django REST

CaracteristicaFastAPIFlaskDjango REST
TipadoNativo (Pydantic)ManualParcial
Docs automaticasSwagger incluidoNoExtension extra
Async nativoSiLimitadoLimitado
Curva de aprendizajeBajaMuy bajaAlta
Ideal paraAPIs modernasApps pequenasProyectos grandes

Preguntas frecuentes sobre FastAPI

¿FastAPI es mejor que Flask para crear APIs?

Para APIs modernas, FastAPI tiene ventajas claras: tipado estático con Pydantic, validación automática, documentación Swagger incluida y soporte async nativo. Flask tiene un ecosistema más maduro y es más sencillo para proyectos pequeños. Si tu objetivo es una API REST que escale, elige FastAPI. Para una app web con algo de API, Flask sigue siendo una buena opción.

¿Para qué sirve Pydantic en FastAPI?

Pydantic es la librería que FastAPI usa para definir y validar modelos de datos. Cada clase que hereda de BaseModel valida automáticamente los tipos, convierte valores compatibles y genera errores descriptivos. Esto elimina el código de validación manual que necesitarías escribir en Flask y garantiza que los datos que llegan a tus endpoints son correctos.

¿Cómo funciona la documentación automática de FastAPI?

FastAPI genera dos interfaces de documentación basándose en las anotaciones de tipo y los modelos Pydantic: Swagger UI en /docs y ReDoc en /redoc. Puedes probar todos los endpoints directamente desde el navegador sin herramientas externas como Postman. La documentación se actualiza automáticamente cada vez que modificas el código.

¿Cuándo usar async def y cuándo def normal en FastAPI?

Usa async def cuando hagas operaciones de I/O que puedan esperar: llamadas a bases de datos asíncronas, peticiones HTTP externas con httpx o lectura de archivos grandes. Para operaciones de base de datos con SQLAlchemy estándar (síncrono), usa def normal. FastAPI gestiona ambas correctamente y puedes mezclarlas en el mismo proyecto sin problemas.

Conclusión

FastAPI es la opción más moderna y productiva para crear APIs con Python en 2026. Si vienes de Flask, la transición es sencilla y los beneficios son inmediatos. Lee también nuestra comparativa Django vs FastAPI vs Flask y los decoradores en Python para entender cómo funcionan internamente los decoradores de rutas.