Al crear la capa de red, este momento llega inevitablemente.
Para enviar una solicitud, hay que añadir el token de autenticación, registrar logs y reintentar si falla.
Si metes todo en una función, send() acaba teniendo 200 líneas.
La herramienta adecuada aquí es el patrón middleware.
La conclusión es esta: en Swift, el middleware resulta más limpio si envuelves cada función con el patrón Decorator y conectas lo envuelto en orden con Chain of Responsibility. No compiten; forman un equipo.
Hoy veremos por qué usar esta combinación y cómo ensamblarla con un ejemplo práctico.
¿Qué es el patrón middleware?
El middleware es una capa intermedia que interviene entre la solicitud y la respuesta.
Si has usado RequestInterceptor de Alamofire o Middleware de Vapor en el servidor, ya conoces el concepto.
La idea central es sencilla.
Mantén intacto el núcleo que procesa la solicitud y permite insertar o retirar funciones antes y después.
Crea autenticación, logging, caché y reintentos como piezas independientes.
Así puedes combinar libremente solo autenticación para una solicitud, o autenticación y caché para otra.
Decorador y cadena de responsabilidad: ¿en qué se diferencian?
Mucha gente confunde estos dos conceptos.
En resumen:
| Distinción | Decorador | Cadena de responsabilidad |
|---|---|---|
| Propósito | Añadir funcionalidad a un objeto existente | Pasar por varios procesadores en orden |
| Relación | Estructura envolvente (anidada) | Estructura conectada (cadena) |
| ¿Continúa? | Siempre pasa al siguiente | Puede detenerse en medio |
| Papel en el middleware | Implementación de cada función | Conectar y ordenar esas funciones |
Al probarlos, descubrí que no se oponen: pertenecen a niveles distintos.
El Decorator responde a «cómo añadir funciones» y la cadena de responsabilidad a «en qué orden ejecutarlas».
Por eso, juntos compensan las debilidades del otro.
Combinación práctica: ensamblémoslos con código
Primero definimos la interfaz común del middleware: recibe una solicitud y la pasa al siguiente middleware.
protocol Middleware {
// requestrecibir la solicitud, procesarla y pasarla, next al siguiente paso
func handle(_ request: Request,
next: (Request) async throws -> Response)
async throws -> Response
}
Ahora creamos cada función como un decorador. Este es el middleware de logging.
struct LoggingMiddleware: Middleware {
func handle(_ request: Request,
next: (Request) async throws -> Response)
async throws -> Response {
print("➡️ solicitud: \(request.url)")
let response = try await next(request) // al siguiente paso
print("⬅️ respuesta: \(response.status)")
return response
}
}
La parte que llama a next(request) es el eslabón de la cadena de responsabilidad.
Hace su trabajo (registrar el log) y pasa el resto al siguiente middleware.
Por último, plegamos varios middlewares en una sola cadena.
func buildChain(_ middlewares: [Middleware],
final: @escaping (Request) async throws -> Response)
-> (Request) async throws -> Response {
middlewares.reversed().reduce(final) { next, mw in
{ req in try await mw.handle(req, next: next) }
}
}
La clave es envolver desde atrás con reduce.
Si insertas el array en orden [인증, 로깅, 재시도], la solicitud lo recorre en ese orden y la respuesta sale en orden inverso. Piensa en las capas de una cebolla.
¿Qué ventajas ofrece este diseño?
Estas son las ventajas que observé al aplicarlo en un proyecto real.
-
Añadir una función consiste en insertar una línea en el array. Si necesitas caché, basta con insertar
CachingMiddleware()en el array. -
Es fácil cambiar el orden. Para ejecutar autenticación antes o después del logging, solo cambia el orden del array.
-
Las pruebas son sencillas. Como cada middleware es independiente, puedes añadir pruebas unitarias por separado.
-
El núcleo queda limpio. El
send()de 200 líneas vuelve a tener menos de diez.
También hay algunos puntos que conviene vigilar.
Cuando hay demasiados middlewares, cuesta seguir por dónde pasa una solicitud.
Por eso, cuando la cadena supera cinco o seis elementos, pongo el middleware de logging al principio y registro la ruta recorrida.
Conclusión
Esta combinación de crear funciones con Decorator y ordenarlas con Chain of Responsibility sirve, una vez dominada, no solo para capas de red, sino también para procesamiento de eventos y validación.
Te recomiendo añadir el ejemplo de hoy a un pequeño proyecto personal. Al quitar las capas directamente, el concepto se asimila mucho más rápido. ¡Feliz refactorización!

