Regístrate para acceder a más de 15 cursos gratuitos de programación con un simulador

Middlewares Python: Desarrollo web con Flask

En una aplicación web, algunas tareas deben ejecutarse en cada request, como validar usuarios, registrar visitas o comprobar parámetros. Repetir código en todas partes no es práctico ni seguro. Para eso existen los middlewares, que nos ayudan a manejar estas tareas de forma centralizada. Veamos cómo funcionan.


¿Qué es un middleware?

El middleware (agente intermedio) es una función que vive entre la llegada de un request y el envío de una respuesta. Se usa para hacer tareas comunes antes o después de procesar el request.
Las middlewares no reemplazan a los handlers (las funciones que responden a los usuarios), sino que los complementan.

Tareas típicas de una middleware

Tarea Cuándo se usa
Verificar acceso Antes del request
Registrar logs Antes o después de cada request
Agregar headers extras Antes de enviar respuesta
Manejar errores Cuando ocurre una excepción en el servidor

¿Cómo funcionan las middlewares?

Supongamos que tenemos esta función:

def add_five(num):
    return num + 5

Si queremos "decorarla" para que antes de sumar 5 primero duplique el número, podríamos hacer esto:

def double_and_add_five(x):
    return add_five(x * 2)

print(double_and_add_five(3))  # Resultado: 11

Lo que hicimos aquí fue envolver la función add_five dentro de otra. Esta técnica se llama composición y es muy similar a cómo funcionan las middlewares.


Flask: Usando middlewares

Flask ya viene listo para usar middlewares. Lo único que tenemos que hacer es usar algunos decoradores especiales:

Decorador Cuándo se ejecuta
@before_request Antes de ejecutar el handler
@after_request Después de ejecutar el handler
@teardown_request Siempre se ejecuta, incluso si hubo un error

Ejemplo básico

from flask import Flask, request

app = Flask(__name__)

@app.before_request
def log_request_path():
    print(f"Path: {request.path}")

@app.after_request
def log_response(response):
    print("Respuesta enviada al cliente")
    return response

@app.route("/")
def home():
    return "Hola, estás en la página principal"

Este código sirve para:

  • Imprimir en consola el path de cada petición.
  • Mostrar un mensaje cuando la respuesta haya sido enviada.

Cada middleware se ejecuta en una cadena (uno tras otro). Flask recorre esa cadena para cada request.

pipeline


Agregar headers con middlewares

También podemos modificar la respuesta desde una middleware, como agregar headers personalizados:

@app.after_request
def add_custom_header(response):
    response.headers["X-Custom-Header"] = "valor"
    return response

Probemos esto con un comando:

curl --head localhost:5000

Y veremos algo como:

HTTP/1.1 200 OK
X-Custom-Header: valor

¿Qué pasa si quiero detener la ejecución?

Hay veces en que no queremos que se siga ejecutando todo el código. Por ejemplo, que se detenga si falta un parámetro obligatorio en la URL.

Podemos hacerlo retornando una respuesta directamente desde una middleware:

@app.before_request
def check_id():
    if request.endpoint == 'resource':
        id = request.args.get("id")
        if not id:
            return 'Falta parámetro "id"', 400
Esto detiene la cadena de funciones y devuelve inmediatamente una respuesta con estado 400 (Bad Request).

Código completo del ejemplo:

from flask import Flask, request

app = Flask(__name__)

@app.before_request
def check_id():
    if request.endpoint == "resource":
        id = request.args.get("id")
        if not id:
            return 'Falta parámetro "id"', 400

@app.route("/resource")
def resource():
    id = request.args.get("id")
    return f"Recurso con id: {id}"

Si ejecutamos:

curl localhost:5000/resource

Veremos:

HTTP/1.1 400 BAD REQUEST
Falta parámetro "id"

Este patrón se conoce como Cadena de Responsabilidad.


Ejecutar código siempre (incluso con errores)

Flask tiene una middleware especial llamada @teardown_request. Se ejecuta al final del ciclo, incluso si ocurrió un error.

@app.teardown_request
def cleanup(exception):
    print("Esto se ejecuta siempre, sin importar si hubo error.")

@app.route("/")
def home():
    raise Exception("¡Algo salió mal!")

Cuando haces un request:

curl -Is localhost:5000/

Aunque veas un error 500, en consola aparecerá:

Esto se ejecuta siempre, sin importar si hubo error.

Relación con los handlers

Ten en cuenta que las funciones que responden a rutas (como @app.route('/') ) también son middlewares, pero esas solo se ejecutan si el request coincide con esa ruta específica.

Flask ejecuta las middlewares en orden:

  1. Todas las middlewares de @before_request
  2. El manejador (@app.route)
  3. Todas las middlewares de @after_request
  4. La middleware @teardown_request

Resumen

  • Los middlewares en Flask son funciones que se ejecutan antes o después de los handlers.
  • @before_request se ejecuta antes de procesar el request.
  • @after_request se ejecuta después de procesar el request y puede modificar la respuesta.
  • @teardown_request siempre se ejecuta, incluso si hubo errores.
  • Un middleware puede detener el flujo retornando una respuesta directamente.

Materiales adicionales

  1. before_request
  2. after_request

Para acceder completo a curso necesitas un plan básico

El plan básico te dará acceso completo a todos los cursos, ejercicios y lecciones de Códica, proyectos y acceso de por vida a la teoría de las lecciones completadas. La suscripción se puede cancelar en cualquier momento.

Obtener acceso
130
cursos
1000
ejercicios
2000+
horas de teoría
3200
test

Obtén acceso

Cursos de programación para principiantes y desarrolladores experimentados. Comienza tu aprendizaje de forma gratuita

  • 130 cursos, 2000+ horas de teoría
  • 1000 ejercicios prácticos en el navegador
  • 360 000 estudiantes
Al enviar el formulario, aceptas el «Política de privacidad» y los términos de la «Oferta», y también aceptas los «Términos y condiciones de uso»

Nuestros graduados trabajan en empresas como:

Bookmate
Health Samurai
Dualboot
ABBYY