¿Qué Es un API Gateway?
Un API gateway es un servidor que se sitúa entre los clientes y los servicios backend, actuando como el punto de entrada único para todas las solicitudes de API. En lugar de que los clientes se comuniquen directamente con múltiples microservicios, envían todas las solicitudes al gateway, que las enruta al servicio apropiado.
Piensa en él como la puerta de entrada a tu arquitectura de microservicios. Maneja preocupaciones transversales — autenticación, limitación de tasa, logging, transformación de solicitudes — para que los servicios individuales no tengan que implementar estas funcionalidades por sí mismos.
Por Qué Existen los API Gateways
Sin un API gateway, una aplicación móvil que llama a 10 microservicios necesitaría:
- Conocer cada URL de servicio: El cliente debe gestionar conexiones a múltiples servicios
- Manejar auth por separado: Cada servicio debe validar tokens independientemente
- Hacer múltiples viajes de ida y vuelta: Una sola pantalla podría requerir llamadas a 5-10 servicios
- Manejar diferencias de protocolo: Algunos servicios usan REST, otros gRPC, algunos WebSocket
Un API gateway centraliza todo esto, dando a los clientes un único endpoint y una API consistente.
Responsabilidades Principales
1. Enrutamiento de Solicitudes
El gateway enruta solicitudes al servicio backend apropiado basándose en la ruta URL, método HTTP, cabeceras u otros atributos. Esto desacopla a los clientes de la topología interna de servicios — los servicios pueden dividirse, fusionarse o moverse sin que los clientes lo sepan.
// API Gateway routing configuration (conceptual)
interface RouteConfig {
path: string;
method: string;
upstream: string;
middleware: string[];
}
const routes: RouteConfig[] = [
{
path: '/api/users/*',
method: 'ALL',
upstream: 'http://user-service:3001',
middleware: ['auth', 'rateLimit', 'logging'],
},
{
path: '/api/orders/*',
method: 'ALL',
upstream: 'http://order-service:3002',
middleware: ['auth', 'rateLimit', 'logging'],
},
{
path: '/api/products/*',
method: 'GET',
upstream: 'http://product-service:3003',
middleware: ['cache', 'rateLimit', 'logging'], // No auth for public product listing
},
];
2. Autenticación y Autorización
El gateway valida tokens de autenticación (JWT, claves de API, tokens OAuth) antes de reenviar solicitudes a los servicios backend. Esto significa que los servicios backend pueden confiar en que todas las solicitudes entrantes han sido autenticadas, simplificando su lógica.
// Authentication middleware in API gateway
import jwt from 'jsonwebtoken';
async function authMiddleware(req: Request, res: Response, next: NextFunction) {
const token = req.headers.authorization?.replace('Bearer ', '');
if (!token) {
return res.status(401).json({ error: 'Authentication required' });
}
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET!);
// Attach user info to headers for downstream services
req.headers['x-user-id'] = decoded.userId;
req.headers['x-user-role'] = decoded.role;
// Remove the original auth header - downstream services
// trust the x-user-* headers set by the gateway
delete req.headers.authorization;
next();
} catch (error) {
if (error.name === 'TokenExpiredError') {
return res.status(401).json({ error: 'Token expired' });
}
return res.status(401).json({ error: 'Invalid token' });
}
}
3. Limitación de Tasa
El gateway impone límites de tasa para proteger los servicios backend de ser saturados. Los límites de tasa pueden aplicarse por usuario, por clave de API, por dirección IP o por endpoint.
4. Transformación de Solicitud/Respuesta
El gateway puede modificar solicitudes antes de reenviarlas y respuestas antes de retornarlas. Esto es útil para versionado de APIs, traducción de protocolos y agregación de respuestas.
// Response aggregation - combine multiple service responses
async function getUserDashboard(req: Request, res: Response) {
const userId = req.headers['x-user-id'];
// Call multiple services in parallel
const [profile, orders, notifications] = await Promise.all([
fetch(`http://user-service:3001/users/${userId}`).then(r => r.json()),
fetch(`http://order-service:3002/users/${userId}/recent`).then(r => r.json()),
fetch(`http://notification-service:3003/users/${userId}/unread`).then(r => r.json()),
]);
// Aggregate into a single response
// Client makes ONE call instead of THREE
res.json({
profile,
recentOrders: orders.slice(0, 5),
unreadNotifications: notifications.count,
});
}
5. Logging y Monitoreo
El gateway es el lugar ideal para registrar todo el tráfico de API porque cada solicitud pasa a través de él. Puedes capturar metadata de solicitud/respuesta, latencia, tasas de error y patrones de uso sin instrumentar cada servicio individual.
Patrones de API Gateway
Backend para Frontend (BFF)
En lugar de un solo gateway para todos los clientes, crea un gateway separado para cada tipo de cliente (web, móvil, terceros). Cada BFF está optimizado para las necesidades de su cliente — el BFF móvil podría agregar más datos por solicitud (para reducir viajes de ida y vuelta en redes lentas), mientras que el BFF web podría retornar respuestas más ricas.
Gateway Offloading
Mueve funcionalidad compartida de los servicios individuales al gateway: terminación SSL, compresión, manejo de CORS, validación de solicitudes. Esto reduce la duplicación y asegura consistencia entre servicios.
Patrón Circuit Breaker
El circuit breaker previene que el gateway reenvíe solicitudes a un servicio que está fallando, lo que desperdiciaría recursos y aumentaría la latencia. Como un interruptor eléctrico, se "dispara" cuando demasiadas solicitudes fallan, y deja de enviar tráfico hasta que el servicio se recupera.
// Circuit Breaker implementation
enum CircuitState {
CLOSED = 'CLOSED', // Normal operation
OPEN = 'OPEN', // Rejecting all requests
HALF_OPEN = 'HALF_OPEN', // Testing if service recovered
}
class CircuitBreaker {
private state: CircuitState = CircuitState.CLOSED;
private failureCount: number = 0;
private successCount: number = 0;
private lastFailureTime: number = 0;
constructor(
private failureThreshold: number = 5,
private recoveryTimeout: number = 30000,
private halfOpenMaxAttempts: number = 3,
) {}
async execute<T>(fn: () => Promise<T>): Promise<T> {
if (this.state === CircuitState.OPEN) {
if (Date.now() - this.lastFailureTime >= this.recoveryTimeout) {
this.state = CircuitState.HALF_OPEN;
this.successCount = 0;
} else {
throw new Error('Circuit breaker is OPEN - service unavailable');
}
}
try {
const result = await fn();
if (this.state === CircuitState.HALF_OPEN) {
this.successCount++;
if (this.successCount >= this.halfOpenMaxAttempts) {
this.state = CircuitState.CLOSED;
this.failureCount = 0;
}
}
return result;
} catch (error) {
this.failureCount++;
this.lastFailureTime = Date.now();
if (this.failureCount >= this.failureThreshold) {
this.state = CircuitState.OPEN;
}
throw error;
}
}
}
Soluciones de API Gateway Comparadas
Comparación de API Gateways
| Característica | Kong | AWS API Gateway | Nginx |
|---|---|---|---|
| Tipo | Open source / Enterprise | Servicio gestionado | Open source |
| Construido sobre | Nginx + Lua | Infraestructura AWS | C (personalizado) |
| Plugins | Rico ecosistema de plugins | Lambda authorizers | Módulos Lua/C |
| Limitación de tasa | Plugin incorporado | Incorporado | Módulo requerido |
| Auth | JWT, OAuth, LDAP, API key | Cognito, Lambda, IAM | Básico, JWT (Plus) |
| Mejor para | Multi-nube, rico en funciones | Serverless nativo de AWS | Proxy inverso simple |
Mejores Prácticas de API Gateway
- Mantén el gateway liviano. Debe enrutar y aplicar preocupaciones transversales, no contener lógica de negocio. La lógica de negocio pertenece a los servicios.
- Evita punto único de fallo. Ejecuta múltiples instancias del gateway detrás de un balanceador de carga o usa un servicio gestionado.
- Implementa timeouts. Establece timeouts agresivos para servicios upstream para prevenir que servicios lentos bloqueen el gateway.
- Usa circuit breakers. Protege el gateway y servicios saludables de fallos en cascada causados por un solo servicio fallando.
- Cachea cuando sea posible. El gateway puede cachear respuestas de servicios upstream para reducir carga y mejorar latencia.
- Versiona tus APIs. Soporta múltiples versiones de API simultáneamente mediante versionado basado en ruta (/v1, /v2) o basado en cabeceras.
Anti-Patrones Comunes
- Gateway Dios: Poner lógica de negocio, transformaciones de datos y orquestación en el gateway. Esto crea un monolito disfrazado de gateway.
- Sin health checks: Enrutar tráfico a servicios sin saber si están saludables lleva a fallos en cascada.
- Sin IDs de correlación: Sin un ID de solicitud fluyendo a través de todos los servicios, depurar solicitudes distribuidas se vuelve casi imposible.
- Ignorar latencia: El gateway agrega latencia a cada solicitud. Monitorea la latencia del gateway por separado de la latencia del servicio.