Patrones de API Gateway: Backend for Frontend, Composición, Agregación y más
Los patrones de API Gateway son patrones arquitectónicos probados que se implementan en el gateway para abstraer la complejidad de los clientes, mejorar el rendimiento y orquestar microservicios. Conocer estos patrones permite tomar decisiones arquitectónicas fundamentadas.
¿Qué son los patrones de API Gateway?
Los patrones de API Gateway son patrones arquitectónicos que utilizan el API Gateway como punto central para resolver problemas recurrentes en la arquitectura de APIs. Definen cómo el gateway transforma, agrega, redirige y asegura las solicitudes, sin que los clientes ni los backends necesiten implementar esta lógica por sí solos.
Los patrones más importantes:
- Backend for Frontend (BFF): Un gateway especializado por tipo de cliente
- API Composition / Aggregation: Múltiples llamadas a backend en una sola solicitud
- Protocol Translation: Conversión de protocolo en el gateway
- Circuit Breaker: Protección contra fallos en cascada
- Strangler Fig: Migración gradual de APIs antiguas
- API Versioning: Versionado y versiones de API en paralelo
- Request/Response Transformation: Adaptación de payloads en el gateway
¿Quién utiliza los patrones de API Gateway?
- Arquitectos de software eligen patrones en función de los requisitos
- Equipos de plataforma implementan patrones como configuración del gateway
- Desarrolladores backend necesitan entender cómo el gateway transforma sus endpoints
- Desarrolladores frontend se benefician de respuestas agregadas y adaptadas
¿Por qué es importante este tema en informática y en exámenes?
Los patrones de API Gateway son conocimientos fundamentales para certificaciones de arquitectura (AWS Solutions Architect, Azure Solutions Architect) y se tratan en detalle en libros sobre microservicios (Sam Newman, Chris Richardson). En exámenes de IHK y en estudios de informática, patrones como BFF y Circuit Breaker se preguntan como ejemplos de patrones de diseño a nivel arquitectónico. Comprender estos patrones es esencial para diseñar landscapes de APIs escalables y mantenibles.
Conceptos clave en detalle
1. Backend for Frontend (BFF)
El patrón BFF establece que cada tipo de cliente obtiene su propio gateway (o su propia configuración de gateway) ajustado exactamente a sus necesidades.
El problema: una aplicación web, una aplicación móvil y un cliente B2B tienen requisitos diferentes. La aplicación web necesita datos completos para UIs complejas. La aplicación móvil necesita datos reducidos para redes lentas. El cliente B2B necesita endpoints de lote y XML. Un único gateway no puede satisfacer óptimamente todos estos requisitos.
La solución: tres BFFs:
- Web-BFF: Respuestas completas, agregaciones complejas, CORS
- Mobile-BFF: Campos reducidos, jerarquías planas, caché, límites de velocidad inferiores
- B2B-BFF: Endpoints de lote, transformación XML, mTLS, cuotas superiores
Cada BFF puede desarrollarse, desplegarse y escalarse de forma independiente.
2. API Composition / Aggregation
El patrón de composición agrupa múltiples solicitudes a backends en una única solicitud de cliente. El cliente envía una solicitud al gateway, el gateway llama a varios backends en paralelo y combina los resultados.
Ejemplo: un cliente llama a /api/dashboard. El gateway llama en paralelo a:
/users/42(User Service)/orders?userId=42(Order Service)/notifications?userId=42(Notification Service)
El gateway combina las tres respuestas en una única respuesta JSON. El cliente realiza un viaje redondo en lugar de tres.
Ventajas: latencia reducida (llamadas paralelas), complejidad de cliente reducida, manejo de errores centralizado. Desventajas: el gateway se vuelve más complejo, el manejo de errores ante fallos parciales es difícil.
3. Protocol Translation
El gateway convierte protocolos entrantes en protocolos internos:
- REST a gRPC: Los clientes externos envían REST, el gateway convierte a gRPC para microservicios internos. gRPC es más eficiente (Protobuf, HTTP/2), pero menos accesible para clientes externos.
- SOAP a REST: Los servicios SOAP heredados se ofrecen como APIs REST modernas hacia afuera.
- HTTP a WebSocket: El gateway mantiene conexiones WebSocket y se comunica internamente sobre HTTP.
- GraphQL a REST: El gateway acepta queries GraphQL y las mapea a llamadas a backends REST.
4. Circuit Breaker
El Circuit Breaker protege el sistema contra fallos en cascada. Tiene tres estados:
- Closed: Las solicitudes se redirigen normalmente. Los errores se cuentan.
- Open: A partir de un umbral de tasa de errores (p. ej., 50% en 10 segundos), todas las solicitudes se rechaza de inmediato con una respuesta de error. El backend ya no se sobrecarga.
- Half-Open: Después de un período de espera (p. ej., 30 segundos), se permite una solicitud de prueba. Si tiene éxito, el breaker vuelve a Closed. Si falla, permanece Open.
El patrón evita que un servicio lento o caído bloquee todo el sistema, porque los clientes esperan timeouts.
5. Strangler Fig
El patrón Strangler Fig permite la migración gradual de una API antigua a una nueva arquitectura. Recibe su nombre de la higuera estranguladora, que crece lentamente alrededor de un árbol y lo reemplaza.
El proceso:
- El gateway redirige todas las solicitudes a la API antigua (Facade).
- Los nuevos endpoints se implementan en el nuevo sistema. El gateway redirige estos al nuevo sistema.
- Gradualmente se migran más endpoints.
- Cuando se han migrado todos los endpoints, se apaga la API antigua.
Ventaja: migración sin lanzamiento de Big-Bang, recuperable, de bajo riesgo.
6. API Versioning en el Gateway
El gateway gestiona múltiples versiones de API en paralelo:
/v1/users-> servicio de usuario antiguo (Legacy)/v2/users-> nuevo servicio de usuario (con campos extendidos)
El gateway puede mapear versiones: una solicitud v1 se transforma para que funcione también en el backend v2 (Forward Compatibility). O el gateway redirige v1 al backend antiguo y v2 al nuevo.
7. Request/Response Transformation
El gateway transforma payloads sin cambiar el backend:
- Reducción de campos: el cliente móvil recibe solo 5 campos en lugar de 20
- Renombramiento de campos:
first_name(externo) afirstName(interno) - Conversión de formato: XML a JSON, snake_case a camelCase
- Enriquecimiento de headers: headers de seguridad, correlation ID, tenant ID
- Filtrado de respuestas: eliminar campos sensibles para determinados clientes
¿Por qué son importantes los patrones de API Gateway en la práctica?
Escenario 1: Rendimiento de aplicación móvil
Una aplicación móvil necesita 3 llamadas API para una pantalla de dashboard. Cada llamada tiene 200ms de latencia. Total: 600ms más renderizado. Con API Composition: 1 llamada, llamadas a backend en paralelo, total: 250ms. La aplicación se siente notablemente más rápida.
Escenario 2: Migración de legacy
Un monolito de 10 años debe migrarse a microservicios. Un lanzamiento de Big-Bang es demasiado riesgoso. Con el patrón Strangler Fig, los endpoints se migran uno a uno, el gateway redirige automáticamente al sistema correcto. Los clientes antiguos no notan nada de la migración.
Escenario 3: Prevenir fallas en cascada
El servicio A llama al servicio B, que está lento. El servicio A espera a que expire el timeout mientras ocupa threads. Múltiples solicitudes se acumulan y el servicio A también se vuelve lento. El Circuit Breaker en el gateway detecta los errores del servicio B, abre el circuito, y el servicio A recibe inmediatamente una respuesta de error en lugar de esperar. El sistema permanece estable.
Ejemplo práctico: Kong API Gateway con Composition y Circuit Breaker
Este ejemplo muestra dos patrones en la práctica: API Composition (un endpoint agrega múltiples llamadas a backends) y Circuit Breaker (protección contra fallos de backends). Se eligió porque estos dos patrones son los más comunes en la práctica y resuelven el mayor problema arquitectónico: complejidad del cliente y resistencia a fallos.
# kong-patterns.yml
# API Gateway Patterns: Composition + Circuit Breaker + BFF
services:
# --- Backend Services ---
- name: user-service
url: http://user-service.internal:3000
- name: order-service
url: http://order-service.internal:3001
- name: notification-service
url: http://notification-service.internal:3002
# --- BFF: Mobile (datos reducidos) ---
- name: mobile-bff
url: http://bff-mobile.internal:4000
routes:
- name: mobile-dashboard
paths:
- /mobile/dashboard
strip_path: false
# --- BFF: Web (datos completos) ---
- name: web-bff
url: http://bff-web.internal:4001
routes:
- name: web-dashboard
paths:
- /web/dashboard
strip_path: false
routes:
# --- Composition Route: /dashboard agrega 3 servicios ---
- name: dashboard-composite
paths:
- /api/dashboard
strip_path: false
service: user-service # Fallback, sobrescrito por plugin
plugins:
# --- Circuit Breaker para todos los servicios ---
- name: request-termination
service: order-service
config:
status_code: 503
message: "Order Service temporarily unavailable"
# --- Rate Limiting por BFF ---
- name: rate-limiting
route: mobile-dashboard
config:
minute: 60
limit_by: ip
- name: rate-limiting
route: web-dashboard
config:
minute: 200
limit_by: consumer
// bff-composition.js
// Backend for Frontend: Dashboard Composition con Circuit Breaker
// Node.js/Express — agrega User, Orders y Notifications
const express = require('express');
const axios = require('axios');
const CircuitBreaker = require('opossum');
const app = express();
// Circuit Breaker para cada servicio
const userBreaker = new CircuitBreaker(async (userId) => {
const res = await axios.get(`http://user-service.internal:3000/users/${userId}`, {
timeout: 2000
});
return res.data;
}, {
timeout: 3000,
errorThresholdPercentage: 50,
resetTimeout: 30000
});
const orderBreaker = new CircuitBreaker(async (userId) => {
const res = await axios.get(`http://order-service.internal:3001/orders?userId=${userId}`, {
timeout: 2000
});
return res.data;
}, {
timeout: 3000,
errorThresholdPercentage: 50,
resetTimeout: 30000
});
const notificationBreaker = new CircuitBreaker(async (userId) => {
const res = await axios.get(`http://notification-service.internal:3002/notifications?userId=${userId}`, {
timeout: 2000
});
return res.data;
}, {
timeout: 3000,
errorThresholdPercentage: 50,
resetTimeout: 30000
});
// Funciones fallback cuando el circuito está abierto
userBreaker.fallback(() => ({ id: null, name: 'Unbekannt', error: 'User Service unavailable' }));
orderBreaker.fallback(() => ({ orders: [], error: 'Order Service unavailable' }));
notificationBreaker.fallback(() => ({ notifications: [], error: 'Notification Service unavailable' }));
// Endpoint de composition: /api/dashboard?userId=42
app.get('/api/dashboard', async (req, res) => {
const userId = req.query.userId;
if (!userId) {
return res.status(400).json({
error: 'MISSING_PARAMETER',
message: 'userId ist erforderlich'
});
}
// Llamadas paralelas con Circuit Breaker
const [user, orders, notifications] = await Promise.all([
userBreaker.fire(userId),
orderBreaker.fire(userId),
notificationBreaker.fire(userId)
]);
// Respuesta agregada
res.json({
user: user,
orders: orders.orders || [],
orderCount: orders.orders ? orders.orders.length : 0,
notifications: notifications.notifications || [],
unreadNotifications: notifications.notifications
? notifications.notifications.filter(n => !n.read).length
: 0,
// Indicador de fallos parciales
_meta: {
userAvailable: !user.error,
ordersAvailable: !orders.error,
notificationsAvailable: !notifications.error,
timestamp: new Date().toISOString()
}
});
});
// Mobile BFF: Campos reducidos
app.get('/mobile/dashboard', async (req, res) => {
const userId = req.query.userId;
const [user, orders, notifications] = await Promise.all([
userBreaker.fire(userId),
orderBreaker.fire(userId),
notificationBreaker.fire(userId)
]);
// Mobile: Solo campos esenciales, estructura plana
res.json({
userName: user.name || 'Unbekannt',
orderCount: orders.orders ? orders.orders.length : 0,
unreadCount: notifications.notifications
? notifications.notifications.filter(n => !n.read).length
: 0
});
});
// Web BFF: Datos completos
app.get('/web/dashboard', async (req, res) => {
const userId = req.query.userId;
const [user, orders, notifications] = await Promise.all([
userBreaker.fire(userId),
orderBreaker.fire(userId),
notificationBreaker.fire(userId)
]);
// Web: Todos los campos, estructura anidada
res.json({
profile: user,
recentOrders: orders.orders || [],
allNotifications: notifications.notifications || [],
_meta: {
userAvailable: !user.error,
ordersAvailable: !orders.error,
notificationsAvailable: !notifications.error
}
});
});
app.listen(4000, () => {
console.log('BFF listening on port 4000');
});
Información detallada
BFF: Cuándo y cuántos necesitas
Regla general: un BFF por tipo de cliente, no por dispositivo. Los BFFs típicos son:
- Web-BFF: Aplicaciones de navegador (SPA, SSR)
- Mobile-BFF: Aplicaciones iOS/Android
- B2B-BFF: Integraciones con socios
No recomendado: un BFF por pantalla o por feature. Esto lleva a una explosión de BFFs y sobrecarga de mantenimiento.
Composition: Síncrona vs. Asíncrona
La composition que se muestra es síncrona (el cliente espera la respuesta). Para composition asíncrona hay dos variantes:
- Request/Reply con WebSocket: El cliente se suscribe al gateway, que llamará a los backends y empujará los resultados tan pronto como estén disponibles.
- Event-Driven: El cliente envía una solicitud, el gateway inicia el procesamiento asíncrono y devuelve un ID de correlación. El cliente consulta o se suscribe al resultado.
Configuración de Circuit Breaker
Parámetros importantes:
- errorThresholdPercentage: Con qué porcentaje de errores se abre el breaker (típicamente: 50%)
- resetTimeout: Cuánto tiempo permanece abierto el breaker (típicamente: 30s)
- timeout: Cuándo se considera que una llamada ha fallado (típicamente: 2-5s)
- volumeThreshold: Número mínimo de llamadas antes de calcular la tasa de errores (típicamente: 5)
Strangler Fig: Riesgos y medidas preventivas
- Lógica duplicada: Durante la migración existe lógica tanto en el sistema antiguo como en el nuevo. Medida preventiva: librerías compartidas para la lógica de negocio.
- Errores de enrutamiento: El gateway dirige las solicitudes al sistema equivocado. Medida preventiva: feature flags y canary releases.
- Consistencia de datos: El sistema antiguo y el nuevo utilizan la misma base de datos o diferentes. Medida preventiva: particionamiento claro de datos o sincronización de modelos de lectura.
Transformación: JSONPath y Templates
Los gateways API modernos soportan transformaciones con JSONPath o templates:
- JSONPath:
$.user.first_nameextrae un campo - JQ: transformaciones complejas con sintaxis jq
- Liquid Templates: motor de plantillas para transformación de respuestas (Azure API Management)
- Lua: Kong/OpenResty permite scripts Lua para transformaciones complejas
Anti-patrones
- Gateway como capa de lógica de negocio: El gateway no debe contener lógica de negocio. Transformación y agregación sí, pero no cálculos o validaciones de dominio.
- Demasiados BFFs: Cada equipo quiere su propio BFF. Esto causa duplicación y sobrecarga de mantenimiento.
- Composición sin timeout: Si un backend es lento, el cliente espera indefinidamente. Cada llamada de composición necesita un timeout.
- Circuit Breaker sin fallback: Sin fallback el cliente recibe un mensaje de error críptico. Define respuestas de fallback significativas.
FAQ: API Gateway Patterns
1. ¿Qué es el patrón Backend for Frontend (BFF)?
2. ¿Qué es la composición de API?
3. ¿Qué es la traducción de protocolos en el gateway API?
4. ¿Cómo funciona un Circuit Breaker?
5. ¿Qué es el patrón Strangler Fig?
6. ¿Cuántos BFFs deberías tener?
7. ¿Qué sucede en la composición si un backend falla?
8. ¿Debería el gateway contener lógica de negocio?
9. ¿Cuál es la diferencia entre composición síncrona y asíncrona?
10. ¿Cómo configuras correctamente un Circuit Breaker?
11. ¿Qué es la transformación de solicitud/respuesta?
12. ¿Qué es el versionado de API en el gateway?
13. ¿Qué es la degradación elegante en el contexto de la composición de API?
14. ¿Cuál es la diferencia entre API Gateway y Service Mesh?
15. ¿Cuál es el anti-patrón más importante en el API Gateway?
Continúa tu camino de aprendizaje en APIs
El siguiente artículo aborda documentación de APIs con Swagger y OpenAPI, donde aprenderás cómo documentar tus APIs de forma clara, legible por máquinas y conforme a estándares.
Fuentes y recursos adicionales
- https://microservices.io/patterns/apigateway.html
- https://samnewman.io/patterns/
- https://docs.konghq.com/hub/
- https://learn.microsoft.com/en-us/azure/api-management/
- https://martinfowler.com/bliki/StranglerFigApplication.html
Libros recomendados para desarrollo de APIs
Keine Bücher für Kategorie "api-development" gefunden.


