FastAPI en 2026: el framework Python para APIs que ya es el estándar

FastAPI lleva unos años siendo la respuesta habitual cuando alguien pregunta "¿qué uso para hacer una API en Python?". No es casualidad. Sebastián Ramírez lo creó con un objetivo claro: aprovechar los type hints de Python para que el código sea, a la vez, el servidor, la validación y la documentación. Y funciona.

En 2026, según las encuestas anuales de JetBrains sobre el estado de Python, FastAPI es el framework más elegido en proyectos nuevos de API. Por delante de Flask y Django REST Framework. Si todavía no lo conoces, o lo usas a medias, este artículo cubre lo que necesitas.

Qué hace diferente a FastAPI

La mayoría de frameworks te obligan a declarar rutas, validar entradas y documentar la API como tres tareas separadas. Con FastAPI escribes los type hints de Python y el framework hace las tres cosas solo.

Está construido sobre Starlette para el servidor HTTP y Pydantic v2 para la validación. Es ASGI, así que soporta async/await de serie. Y no hay decoradores mágicos ni ficheros de configuración XML: lo que escribes es lo que obtienes.

La estructura básica

Una aplicación mínima tiene este aspecto:

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def root():
    return {"mensaje": "hola"}

Para arrancar el servidor de desarrollo:

uvicorn main:app --reload

El flag --reload reinicia el proceso cada vez que guardas. En producción lo quitas y configuras workers con Gunicorn o directamente con uvicorn en modo multi-worker.

En cuanto a los tipos de retorno, puedes devolver un diccionario, un modelo Pydantic o una Response explícita si necesitas controlar las cabeceras o el código de estado manualmente.

Parámetros de ruta, query y body

FastAPI distingue entre tipos de parámetros según cómo los declares:

Parámetros de ruta

@app.get("/users/{id}")
def get_user(id: int):
    ...

El tipo int hace dos cosas: valida que lo que llegue en la URL sea un número y convierte el string automáticamente.

Parámetros query

@app.get("/users")
def list_users(page: int = 1, limit: int = 10):
    ...

Si tienen valor por defecto, son opcionales. Sin valor por defecto, son obligatorios. FastAPI genera la documentación correspondiente sin que tengas que escribir nada más.

Body

@app.post("/users")
def create_user(user: CreateUserRequest):
    ...

Si el parámetro es un modelo Pydantic, FastAPI lo lee del cuerpo de la petición.

Headers y cookies

from fastapi import Header

@app.get("/me")
def me(token: str = Header(...)):
    ...

Los tres puntos (...) indican que el parámetro es obligatorio. Lo mismo funciona con Cookie, Query y Path si quieres añadir validaciones extra como longitudes mínimas o rangos numéricos.

Modelos Pydantic: validación automática

Pydantic v2 es significativamente más rápido que v1 y tiene una API más limpia. Un modelo típico:

from pydantic import BaseModel, EmailStr, Field

class CreateUserRequest(BaseModel):
    nombre: str
    email: EmailStr
    edad: int = Field(ge=18)

Si mandas un body con edad: 15, FastAPI devuelve un 422 con el detalle exacto del error. No tienes que escribir ni una línea de validación manual.

En el lado de la respuesta, response_model le dice a FastAPI qué campos devolver y cuáles filtrar:

@app.get("/users/{id}", response_model=UserResponse)
def get_user(id: int):
    user = db.get(id)
    return user  # FastAPI serializa y filtra según UserResponse

Esto es útil cuando tu modelo interno tiene campos que no quieres exponer, como contraseñas hasheadas o campos internos de auditoría.

Dependencias: el sistema de inyección de FastAPI

El sistema de dependencias de FastAPI es una de sus partes más potentes y, al principio, la más rara de entender. La idea es simple: declaras una función que provee algo (una conexión a base de datos, el usuario actual, una configuración) y FastAPI la llama antes de ejecutar tu endpoint.

El caso más habitual es la conexión a base de datos:

from sqlalchemy.orm import Session

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

@app.get("/users")
def list_users(db: Session = Depends(get_db)):
    return db.query(User).all()

El yield hace que FastAPI ejecute el código de limpieza (db.close()) una vez que el endpoint termina, aunque haya habido un error.

Las dependencias pueden anidarse: una dependencia puede tener sus propias dependencias, y FastAPI construye el árbol y lo resuelve en orden. Para autenticación, el patrón habitual es:

from fastapi.security import OAuth2PasswordBearer

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

def current_user(token: str = Depends(oauth2_scheme)):
    # validar el token y devolver el usuario
    ...

@app.get("/profile")
def profile(user = Depends(current_user)):
    return user

Rutas async y la integración con asyncio

FastAPI maneja bien tanto los endpoints síncronos como los asíncronos, pero hay que entender la diferencia para no cometer errores de rendimiento.

  • async def: el endpoint se ejecuta en el event loop. Úsalo cuando hagas I/O asíncrono (consultas a base de datos con asyncpg, llamadas HTTP con httpx, etc.).
  • def normal: FastAPI lo ejecuta en un thread pool para no bloquear el event loop. Úsalo con librerías síncronas como SQLAlchemy clásico o requests.
@app.get("/datos")
async def datos():
    resultado = await fetch_from_db()
    return resultado

El error típico es mezclar: llamar a una función síncrona bloqueante dentro de un async def. Eso bloquea el event loop entero. Si tienes que mezclar, usa asyncio.run_in_executor para mover el trabajo síncrono a un thread.

OpenAPI automático: la documentación que se escribe sola

Nada más arrancar la aplicación, FastAPI expone dos URLs:

  • /docs: Swagger UI interactivo. Puedes hacer peticiones reales desde el navegador.
  • /redoc: ReDoc, más limpio para leer la especificación.

Ambos se generan automáticamente a partir de tus type hints y modelos Pydantic. Si añades metadatos a las rutas, aparecen en la documentación:

@app.get(
    "/users",
    summary="Lista de usuarios",
    tags=["users"],
    response_model=list[UserResponse],
    status_code=200
)
def list_users():
    ...

En proyectos con varios desarrolladores o con clientes externos que consumen la API, esto ahorra mucho tiempo. La especificación OpenAPI generada también sirve para generar clientes en otros lenguajes con herramientas como openapi-generator.

Testing con TestClient y httpx

FastAPI incluye un cliente de testing que no necesita levantar un servidor real:

from fastapi.testclient import TestClient

client = TestClient(app)

def test_get_user():
    response = client.get("/users/1")
    assert response.status_code == 200
    assert response.json()["id"] == 1

Los tests son rápidos porque no hay puertos ni red de por medio: el cliente habla directamente con la app ASGI.

Para tests asíncronos, el combo habitual es pytest-asyncio con httpx.AsyncClient:

import pytest
import httpx
from httpx import ASGITransport

@pytest.mark.asyncio
async def test_async_endpoint():
    async with httpx.AsyncClient(
        transport=ASGITransport(app=app),
        base_url="http://test"
    ) as client:
        response = await client.get("/datos")
        assert response.status_code == 200

Con este enfoque puedes testear endpoints asíncronos sin ningún servidor, igual de rápido que los tests síncronos.

Por dónde seguir

Si ya tienes la API levantada y quieres ir más lejos, estos artículos te pueden venir bien:

Imagen: Pexels / Kevin Ku

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP