Introducción: ¿por qué su proyecto necesita un API Gateway?
\n\nImagine: está escribiendo una startup o una aplicación empresarial en TypeScript. Ya tiene un servicio de usuarios, un servicio de pedidos y un servicio de notificaciones. Cada uno vive en su propio puerto (o incluso en su propio servidor), se comunica por HTTP y utiliza su propia base de datos. Todo funciona, pero el cliente (frontend, aplicación móvil) comienza a asfixiarse: para cargar la página de perfil, necesita hacer 4-5 solicitudes a diferentes servicios, lidiar con diferentes formatos de error y además autenticarse en cada uno.
\n\nAquí entra en escena el API Gateway — un punto de entrada único para todos los clientes. Se encarga del enrutamiento, la autenticación, la agregación de datos, el almacenamiento en caché e incluso la transformación de respuestas. En este artículo escribiremos un API Gateway real en TypeScript desde cero, analizaremos patrones y antipatrones, y mostraremos cómo no pisar el rastrillo.
\n\nQué es un API Gateway en palabras sencillas
\n\nUn API Gateway es una capa intermedia entre el cliente y sus servicios internos. El cliente (navegador, aplicación móvil, API externa) solo se comunica con el Gateway. El Gateway observa la ruta de la solicitud, verifica el token y redirige la solicitud al microservicio correspondiente. A veces incluso combina la respuesta de varios servicios en una sola — esto se llama agregación.
\n\n¿Por qué es necesario en el ecosistema TypeScript? Porque TypeScript nos proporciona tipos, interfaces y rigor, y el Gateway es el lugar ideal para la validación y la conversión de datos a un contrato unificado.
\n\nArquitectura: cómo funciona en TypeScript
\n\nDiseñemos una arquitectura simple pero funcional. Tendremos:
\n\n- \n
- Gateway (nuestro servicio TypeScript) — puerto 3000, punto de entrada único. \n
- Servicio de usuarios (User Service) — puerto 4001, API REST. \n
- Servicio de pedidos (Order Service) — puerto 4002, API REST. \n
- Servicio de notificaciones (Notification Service) — puerto 4003, API REST. \n
Todos los servicios internos viven en su propia red (por ejemplo, Docker network) y no son visibles desde el exterior. El cliente solo se comunica con el Gateway.
\n\n// Estructura del proyecto\ngateway/\n├── src/\n│ ├── routes/\n│ │ ├── userRoutes.ts\n│ │ ├── orderRoutes.ts\n│ │ └── notificationRoutes.ts\n│ ├── middleware/\n│ │ ├── authMiddleware.ts\n│ │ ├── rateLimiter.ts\n│ │ └── cacheMiddleware.ts\n│ ├── services/\n│ │ └── proxyService.ts\n│ ├── types/\n│ │ └── index.ts\n│ └── index.ts\n├── package.json\n└── tsconfig.json\n\n\nEscribiendo un API Gateway básico en TypeScript
\n\nEmpecemos instalando las dependencias. Necesitaremos Express (el framework más popular), http-proxy-middleware para el proxy y algunas utilidades.
\n\nnpm init -y\nnpm install express http-proxy-middleware cors helmet express-rate-limit\nnpm install -D typescript @types/node @types/express ts-node nodemon\n\n\nCreemos el tsconfig.json:
{\n "compilerOptions": {\n "target": "ES2020",\n "module": "commonjs",\n "outDir": "./dist",\n "rootDir": "./src",\n "strict": true,\n "esModuleInterop": true,\n "skipLibCheck": true,\n "forceConsistentCasingInFileNames": true\n },\n "include": ["src/**/*"],\n "exclude": ["node_modules"]\n}\n\n\nAhora escribamos el archivo principal src/index.ts:
import express, { Request, Response } from 'express';\nimport cors from 'cors';\nimport helmet from 'helmet';\nimport { createProxyMiddleware } from 'http-proxy-middleware';\nimport { authMiddleware } from './middleware/authMiddleware';\nimport { rateLimiter } from './middleware/rateLimiter';\n\nconst app = express();\nconst PORT = process.env.PORT || 3000;\n\n// Middleware globales\napp.use(helmet());\napp.use(cors());\napp.use(express.json());\napp.use(rateLimiter);\n\n// Proxy para el servicio de usuarios\napp.use('/api/users', auth