Python Flask Microservices en la práctica: el código y los comandos que realmente importan

Python Flask Microservices : lo esencial en un artículo — código real, diagramas y pasos concretos, extractos de un curso de 24 lecciones.

Python Flask Microservices en la práctica: el código y los comandos que realmente importan

Sin teoría interminable aquí: abrimos la terminal y practicamos. Aquí lo esencial de Python Flask Microservices, extraído directamente de un curso completo de 24 lecciones — con código real que puedes copiar y pegar ahora.

tl;dr
  • Flask fundamentals
  • Architecture microservices
  • Communication REST
  • Message bus async
  • gRPC entre services
~$ cat ./parcours.md # Python Flask Microservices — 8 capítulos
01
Flask fundamentals
→ Flask vs Django vs FastAPI→ Primera app y blueprints+ 1 más lecciones
02
Architecture microservices
→ Monolith vs microservices→ Descomponer por dominio (DDD)+ 1 más lecciones
03
Communication REST
→ HTTP síncrono con requests/httpx→ Retry, circuit breaker, timeout+ 1 más leçons
04
Message bus async
→ RabbitMQ et pika→ Kafka para event streaming+ 1 más leçons
05
gRPC entre services
→ Protobuf et grpcio→ Streaming bidireccional+ 1 más leçons
06
Orchestration
→ Docker Compose multi-services→ Kubernetes basics+ 1 más leçons
07
Observabilité
→ Logging centralizado→ Distributed tracing+ 1 más leçons
08
Proyecto final e-commerce
→ Descomposición en servicios→ Implementación servicios + Gateway+ 1 más leçons
🏁
Proyecto final
→ Te vas con un proyecto concreto y demostrable

Monolito vs microservicios

Monolito

output
+----------------------------------------+
|        Application monolithique         |
|  +-----+  +-------+  +-------+          |
|  | UI  |  | Auth  |  | Order |  ...     |
|  +-----+  +-------+  +-------+          |
|  +----------------------------------+   |
|  |           Database               |   |
|  +----------------------------------+   |
+----------------------------------------+

# 1 codebase, 1 deployment, 1 DB
# Todas las funciones en el mismo proceso

Microservicios

output
+---------------+  +---------------+  +---------------+
| Auth Service  |  | Order Service |  | Email Service |
| +DB users     |  | +DB orders    |  | +SMTP         |
+---------------+  +---------------+  +---------------+
        |                 |                  |
        +--------+--------+------------------+
                 |
        +--------+--------+
        | Message Broker  |
        | (Kafka/RabbitMQ)|
        +-----------------+

# N services, N deployments, N DBs (1 par service)
# Comunicación vía HTTP/gRPC/events

Comparación

CriterioMonolitoMicroservicios
Velocidad de desarrollo (inicio)RápidaLenta (sobrecarga)
Velocidad de desarrollo (1000+ devs)Lenta (conflictos)Rápida (aislamiento)
DespliegueTodo o nadaIndependiente por servicio
EscaladoVertical/toda la appHorizontal por servicio
Stack tecnológicoUniformePolíglota
Base de datos1 compartida1 por servicio
PruebasSimplesComplejas (integración)
DepuraciónStack trace claraDistributed tracing
Operaciones1 cosaN cosas (k8s)
LatenciaIn-process (µs)Network (ms)
Modo de falloTodo caeParcial (degradado)

¿Cuándo monolito?

NOTEElige monolito si:
  • Equipo < 20 devs
  • MVP / startup en fase temprana
  • Dominio aún no claro
  • No se necesita escalado extremo
  • Operaciones limitadas (sin devops dedicado)

¿Cuándo microservicios?

NOTEElige microservicios si:
  • Equipos numerosos y autónomos (>50 devs)
  • Dominio bien comprendido, boundaries claros
  • Componentes con necesidades de escalado distintas
  • Stack políglota necesario
  • Capacidad de gestionar la complejidad ops

"Modular monolith": el punto dulce 2026

output
# Estructura de un monolito modular
myapp/
  modules/
    auth/
      api/
      services/
      models/
      tests/
    orders/
      api/
      services/
      models/
      tests/
    notifications/
  shared/
    db/
    events/        # bus interno
    logging/

# 1 deployment, pero fronteras claras
# Comunicación vía events (in-process)
# Facilita la extracción futura a microservicios

Costes ocultos de los microservicios

Patrones arquitectónicos

output
+-----------------+
|   API Gateway   |    <-- punto de entrada único
+-----------------+
        |
+-------+-------+-------+
|       |       |       |
v       v       v       v
+----+ +-----+ +-----+ +------+
|Auth| |User | |Cart | |Order |    <-- microservicios
+----+ +-----+ +-----+ +------+
   |       |      |       |
   v       v      v       v
+----+ +-----+ +-----+ +------+
|DB1 | |DB2  | |Redis| |DB3   |    <-- cada uno su DB
+----+ +-----+ +-----+ +------+
                        |
                        v
                 +-------------+
                 | Kafka/MQ    |    <-- events async
                 +-------------+

Strangler Pattern (migración)

output
# Migrar progresivamente monolito -> microservicios

# Paso 0: Monolito
#   client -> monolito

# Paso 1: Extraer User Service
#   client -> API Gateway
#                |-- /users/* -> user-service (nuevo)
#                |-- /*       -> monolito (resto)

# Paso 2: Extraer Order Service
#   client -> API Gateway
#                |-- /users/*  -> user-service
#                |-- /orders/* -> order-service
#                |-- /*        -> monolito

# ... etc hasta el desmantelamiento total del monolito

Resumen

NOTEPara recordar
  • Monolito = empieza aquí, evoluciona a microservicios si es necesario
  • Microservicios = impuesto de complejidad pero escalado/autonomía
  • "Modular monolith" suele ser el buen compromiso
  • Coste oculto: red, consistencia, ops
  • Strangler pattern para migrar progresivamente

Flask vs Django vs FastAPI

Tabla comparativa

AspectoFlaskDjangoFastAPI
FilosofíaMicro, minimalistaBatteries includedModerno, async
ORMSQLAlchemy (libre)Django ORMSQLAlchemy/Tortoise
AdminNo (Flask-Admin)Auto-generadoNo
AuthFlask-LoginIntegrado completoJWT/OAuth (manual)
AsyncLimitado (3.0+)ParcialNativo
ValidaciónMarshmallow/PydanticForms/SerializersPydantic nativo
OpenAPIFlask-Smorestdrf-spectacularAuto-generado
RendimientoBuenoBuenoExcelente (async)
Curva de aprendizajeMuy fácilModeradaFácil
Casos de usoMicroservicios, APIsApps web complejasAPIs modernas

¿Cuándo elegir Flask?

NOTEIdeal para:
  • Microservicios (ligero, arranque rápido)
  • APIs JSON simples sin necesidad de admin
  • Apps de prototipado rápido
  • Backend para SPA React/Vue con API REST
  • Webhook receivers, bots, jobs HTTP
  • Migración progresiva desde legacy
NOTENo ideal para:
  • Aplicaciones con mucho CRUD admin
  • Necesidad de auth/permissions/migrations integrados
  • Equipos que prefieren un framework opinionated

Hello World comparativo

output
# Flask
from flask import Flask
app = Flask(__name__)

@app.route("/hello")
def hello():
    return {"message": "Hello"}

# 5 líneas, 1 archivo, se ejecuta con: flask run
output
# FastAPI (para comparar)
from fastapi import FastAPI
app = FastAPI()

@app.get("/hello")
async def hello():
    return {"message": "Hello"}

# uvicorn main:app
output
# Django REST Framework (para comparar)
# Requiere: settings.py, urls.py, views.py, manage.py...
# Mucho más boilerplate pero ENORMES funcionalidades

Instalación de Flask

output
python -m venv .venv
source .venv/bin/activate              # Linux/Mac
.venv\Scripts\activate                 # Windows

pip install flask

# O con dependencias clásicas de microservicio
pip install flask gunicorn requests sqlalchemy alembic \
            marshmallow flask-marshmallow flask-smorest \
            python-dotenv pytest

# Lanzar en dev
flask --app app run --debug --port 5000

Stack Flask moderna 2026

output
# Stack de microservicio en producción
flask                       # framework
flask-smorest               # API + OpenAPI auto
marshmallow                 # serialization (o Pydantic)
sqlalchemy[asyncio]         # ORM
alembic                     # migraciones
gunicorn                    # WSGI prod
gevent                      # async workers
httpx                       # cliente HTTP moderno
pydantic-settings           # config 12-factor
prometheus-flask-exporter   # métricas
sentry-sdk[flask]           # errores
opentelemetry-instrumentation-flask  # trazas
pytest pytest-cov           # tests

Ecosistema Flask

WSGI: Flask = síncrono por defecto

output
# Flask 3.0+ soporta async views
@app.route("/async-data")
async def get_data():
    data = await fetch_from_api()
    return data

# PERO sigue siendo WSGI: cada async view bloquea un worker thread
# Para async real: usar ASGI (FastAPI, Quart) o Gunicorn+gevent

gunicorn --worker-class gevent --workers 4 app:app
# gevent hace que las I/O sean no bloqueantes incluso con views sync

Despliegue K8s + tests de integración

Proyecto final • CI/CD • E2E

Pruebas unitarias

output
# services/order/tests/test_order_service.py
import pytest
from unittest.mock import Mock

def test_place_order_creates_order_and_outbox(db, app):
    cart_client = Mock()
    cart_client.get.return_value = {"items": [{"product_id": "p1", "qty": 2}]}
    
    catalog_client = Mock()
    catalog_client.get_product.return_value = {
        "id": "p1", "name": "Book", "price_cents": 1500,
    }
    
    service = OrderService(db, cart_client, catalog_client)
    order = service.place_order(user_id="user-1")
    
    assert order.total_cents == 3000
    assert len(order.items) == 1
    
    # Verificar outbox
    events = Outbox.query.all()
    assert len(events) == 1
    assert events[0].event_type == "order.created"
    assert events[0].payload["total_cents"] == 3000
    cart_client.clear.assert_called_once_with("user-1")

def test_empty_cart_raises():
    cart_client = Mock()
    cart_client.get.return_value = {"items": []}
    
    service = OrderService(db, cart_client, Mock())
    with pytest.raises(ValidationError):
        service.place_order("user-1")

Pruebas de integración multi-servicio

output
# tests/integration/test_e2e_checkout.py
import pytest, httpx, time

# conftest.py inicia docker-compose
@pytest.fixture(scope="session")
def stack():
    subprocess.run(["docker", "compose", "up", "-d", "--wait"], check=True)
    yield
    subprocess.run(["docker", "compose", "down", "-v"])

def test_full_checkout_flow(stack):
    base = "http://localhost"
    
    # 1. Signup
    r = httpx.post(f"{base}/api/auth/signup", json={
        "email": "alice@x.com", "password": "pass", "name": "Alice",
    })
    assert r.status_code == 201
    token = r.json()["access_token"]
    headers = {"Authorization": f"Bearer {token}"}
    
    # 2. List products
    r = httpx.get(f"{base}/api/products")
    product = r.json()["items"][0]
    
    # 3. Add to cart
    r = httpx.post(
        f"{base}/api/cart/items",
        json={"product_id": product["id"], "qty": 2},
        headers=headers,
    )
    assert r.status_code == 200
    
    # 4. Checkout
    r = httpx.post(f"{base}/api/checkout", headers=headers)
    assert r.status_code == 201
    order_id = r.json()["order_id"]
    
    # 5. Esperar procesamiento asíncrono (saga)
    for _ in range(30):        # máx 30s
        r = httpx.get(f"{base}/api/orders/{order_id}", headers=headers)
        if r.json()["status"] == "paid":
            break
        time.sleep(1)
    else:
        pytest.fail("Order never reached 'paid' status")

Pruebas de contrato (Pact)

output
# Verificar que el contrato REST entre consumer (web-gateway) y provider (catalog) se mantiene

from pact import Consumer, Provider

pact = Consumer("web-gateway").has_pact_with(Provider("catalog"), pact_dir="./pacts")

def test_get_product_contract():
    expected = {
        "id": "p1", "name": "Book", "price_cents": 1500, "stock": 10,
    }
    pact.given("product p1 exists") \
        .upon_receiving("a request for product p1") \
        .with_request("GET", "/products/p1") \
        .will_respond_with(200, body=expected)
    
    with pact:
        result = catalog_client.get_product("p1")
        assert result == expected

# Pact file generado -> subido a Pact Broker
# Provider relee el pact -> verifica su API

Dockerfile de producción

output
# services/*/Dockerfile
FROM python:3.12-slim AS deps
WORKDIR /app
RUN pip install --no-cache-dir uv
COPY requirements.txt .
RUN uv pip install --system --no-cache -r requirements.txt

FROM python:3.12-slim
RUN useradd -m -u 1000 app
USER app
WORKDIR /app

COPY --from=deps /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
COPY --from=deps /usr/local/bin/gunicorn /usr/local/bin/gunicorn
COPY src/ ./src/

ENV PYTHONUNBUFFERED=1 PYTHONDONTWRITEBYTECODE=1
EXPOSE 5000

HEALTHCHECK --interval=10s CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:5000/health')"

CMD ["gunicorn", "-c", "gunicorn.conf.py", "src.wsgi:app"]

CI/CD GitHub Actions

output
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        service: [auth, catalog, cart, order, payment, notification]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with: {python-version: "3.12"}
      
      - name: Install deps
        working-directory: services/${{ matrix.service }}
        run: |
          pip install -e ../../shared
          pip install -r requirements.txt
          pip install pytest pytest-cov ruff mypy
      
      - name: Lint
        working-directory: services/${{ matrix.service }}
        run: |
          ruff check src
          mypy src
      
      - name: Tests
        working-directory: services/${{ matrix.service }}
        run: pytest --cov=src --cov-report=xml
      
      - uses: codecov/codecov-action@v4
  
  integration:
    runs-on: ubuntu-latest
    needs: test
    steps:
      - uses: actions/checkout@v4
      - name: Start stack
        run: docker compose up -d --wait
      - name: Run integration tests
        run: pytest tests/integration/
      - name: Logs on failure
        if: failure()
        run: docker compose logs

CD: build + push + deploy

output
# .github/workflows/cd.yml
name: CD
on:
  push:
    tags: ["v*"]

jobs:
  build:
    strategy:
      matrix:
        service: [auth, catalog, cart, order, payment, notification]
    steps:
      - uses: actions/checkout@v4
      - uses: docker/setup-buildx-action@v3
      - uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      
      - name: Build & push
        uses: docker/build-push-action@v5
        with:
          context: services/${{ matrix.service }}
          push: true
          tags: |
            ghcr.io/myorg/${{ matrix.service }}:${{ github.ref_name }}
            ghcr.io/myorg/${{ matrix.service }}:latest
          cache-from: type=gha
          cache-to: type=gha,mode=max
  
  deploy:
    needs: build
    environment: production
    steps:
      - uses: actions/checkout@v4
      - uses: azure/setup-helm@v4
      - name: Deploy via Helm
        run: |
          helm upgrade --install ecommerce ./k8s/charts/umbrella \
            -f ./k8s/values-prod.yaml \
            --set global.imageTag=${{ github.ref_name }} \
            --namespace prod \
            --atomic --timeout 10m
va-más-lejos

Este artículo cubre los extractos más útiles — el curso completo Python Flask Microservices (8 capítulos, 24 lecciones, ejercicios corregidos y proyecto final) te lleva hasta el final.

./acceder-al-curso-completo curso gratuito: Vibe Coding

FAQ

¿Cuánto tiempo se necesita para aprender Python Flask Microservices?
Con una progresión estructurada (8 capítulos, 24 lecciones cortas y prácticas), se alcanza un nivel operativo en unas semanas a razón de 30 a 60 minutos al día. Lo importante es practicar cada noción inmediatamente.
¿Se necesitan requisitos previos?
Basta con nociones básicas de informática. Si sabes usar una terminal y leer código simple, estás listo.
¿Por dónde empezar concretamente?
Reproduce los comandos de este artículo y sigue el curso completo Python Flask Microservices: encadena las 24 lecciones en orden, con ejercicios y proyecto final.

📬 ¿Quieres recibir este tipo de guía cada semana? Suscríbete gratis — código real, cero palabrería.