Introdução: por que seu projeto precisa de um API Gateway?
\n\nImagine: você está desenvolvendo uma startup ou aplicação corporativa em TypeScript. Você já tem um serviço de usuários, um serviço de pedidos e um serviço de notificações. Cada um deles vive em sua própria porta (ou até mesmo em seu próprio servidor), comunicam-se via HTTP, usam seu próprio banco de dados. Tudo funciona, mas o cliente (frontend, aplicativo móvel) começa a sofrer: para montar a página de perfil, ele precisa fazer 4-5 requisições para serviços diferentes, lidar com diferentes formatos de erro e ainda autenticar-se em cada um.
\n\nÉ aí que entra o API Gateway — um ponto de entrada único para todos os clientes. Ele assume o roteamento, autenticação, agregação de dados, cache e até transformação de respostas. Neste artigo, escreveremos um API Gateway real em TypeScript do zero, abordaremos padrões e antipadrões, e mostraremos como não pisar na bola.
\n\nO que é um API Gateway em termos simples
\n\nAPI Gateway é uma camada entre o cliente e seus serviços internos. O cliente (navegador, aplicativo móvel, API externa) se comunica apenas com o Gateway. O Gateway analisa o caminho da requisição, verifica o token e redireciona a requisição para o microsserviço correto. Às vezes, ele até combina a resposta de vários serviços em uma única — isso é chamado de agregação.
\n\nPor que isso é necessário no ecossistema TypeScript? Porque o TypeScript nos fornece tipos, interfaces e rigor, e o Gateway é o local ideal para validação e padronização dos dados em um contrato único.
\n\nArquitetura: como funciona em TypeScript
\n\nVamos projetar uma arquitetura simples, mas funcional. Teremos:
\n\n- \n
- Gateway (nosso serviço TypeScript) — porta 3000, ponto de entrada único. \n
- Serviço de Usuários (User Service) — porta 4001, REST API. \n
- Serviço de Pedidos (Order Service) — porta 4002, REST API. \n
- Serviço de Notificações (Notification Service) — porta 4003, REST API. \n
Todos os serviços internos vivem em sua própria rede (por exemplo, Docker network) e não são visíveis externamente. O cliente se comunica apenas com o Gateway.
\n\n// Estrutura do projeto\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\nEscrevendo um API Gateway básico em TypeScript
\n\nVamos começar instalando as dependências. Precisaremos do Express (o framework mais popular), http-proxy-middleware para proxy e algumas 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\nCriaremos o 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\nAgora escreveremos o arquivo 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// Middlewares globais\napp.use(helmet());\napp.use(cors());\napp.use(express.json());\napp.use(rateLimiter);\n\n// Proxy para o serviço de usuários\napp.use('/api/users', auth