Pular para o conteúdoPedro Farbo

API Gateway com Kong: Guia Completo para Microserviços

Aprenda a implementar um API Gateway robusto com Kong para gerenciar seus microserviços, incluindo autenticação, rate limiting, load balancing e observabilidade.

Este conteúdo é gratuito! Ajude a manter o projeto no ar.

PIX:0737160d-e98f-4a65-8392-5dba70e7ff3e

No artigo anterior sobre microserviços, construímos um serviço de usuários seguindo Clean Architecture e DDD. Agora, vamos implementar um API Gateway com Kong para gerenciar a comunicação entre clientes e nossos microserviços.

O que é um API Gateway?

Um API Gateway é o ponto de entrada único para todas as requisições de clientes aos seus microserviços. Ele atua como um proxy reverso que roteia requisições, agrega respostas e fornece funcionalidades cross-cutting.

┌─────────────────────────────────────────────────────────────────────┐
│                           Clients                                    │
│                  (Web, Mobile, IoT, Partners)                        │
└─────────────────────────────────────────────────────────────────────┘
                                  │
                                  ▼
┌─────────────────────────────────────────────────────────────────────┐
│                         API Gateway (Kong)                           │
│  ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────────┐   │
│  │  Auth   │ │  Rate   │ │  Load   │ │ Logging │ │   Request   │   │
│  │         │ │ Limiting│ │Balancing│ │         │ │ Transform   │   │
│  └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────────┘   │
└─────────────────────────────────────────────────────────────────────┘
                                  │
                    ┌─────────────┼─────────────┐
                    ▼             ▼             ▼
              ┌──────────┐ ┌──────────┐ ┌──────────┐
              │  User    │ │  Order   │ │ Product  │
              │ Service  │ │ Service  │ │ Service  │
              └──────────┘ └──────────┘ └──────────┘

Por que Kong?

Kong é um dos API Gateways mais populares e robustos do mercado:

Benefícios

CaracterísticaDescrição
Alta PerformanceConstruído em Nginx/OpenResty, suporta milhões de requests/segundo
Extensível100+ plugins oficiais e suporte a plugins customizados (Lua, Go, JavaScript)
Cloud NativeIntegração nativa com Kubernetes, Helm charts oficiais
Open SourceVersão gratuita com todas funcionalidades essenciais
DB-less ModePode rodar sem banco de dados, usando apenas configuração declarativa
Multi-protocolHTTP, gRPC, WebSocket, TCP/UDP

Kong vs Alternativas

GatewayPontos FortesPontos Fracos
KongPerformance, extensibilidade, comunidadeCurva de aprendizado
AWS API GatewayIntegração AWS, serverlessVendor lock-in, custo
TraefikSimples, auto-discoveryMenos plugins
NGINXPerformanceRequer mais configuração manual
EnvoyService mesh, observabilidadeComplexidade

Arquitetura do Kong

┌─────────────────────────────────────────────────────────────────┐
│                        Kong Gateway                              │
│                                                                  │
│  ┌────────────────────────────────────────────────────────────┐ │
│  │                      Kong Proxy                             │ │
│  │                    (Port 8000/8443)                         │ │
│  │  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐       │ │
│  │  │ Plugin  │→ │ Plugin  │→ │ Plugin  │→ │ Plugin  │→ ...  │ │
│  │  │  Auth   │  │  Rate   │  │  Log    │  │Transform│       │ │
│  │  └─────────┘  └─────────┘  └─────────┘  └─────────┘       │ │
│  └────────────────────────────────────────────────────────────┘ │
│                                                                  │
│  ┌────────────────────────────────────────────────────────────┐ │
│  │                      Kong Admin API                         │ │
│  │                    (Port 8001/8444)                         │ │
│  └────────────────────────────────────────────────────────────┘ │
│                                                                  │
│  ┌────────────────────────────────────────────────────────────┐ │
│  │                      Data Store                             │ │
│  │              (PostgreSQL / Cassandra / DB-less)             │ │
│  └────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘

Conceitos Fundamentais

  • Services: Representam seus microserviços upstream
  • Routes: Definem como as requisições chegam aos services
  • Consumers: Representam usuários ou aplicações que consomem suas APIs
  • Plugins: Adicionam funcionalidades (auth, rate limiting, logging, etc.)
  • Upstreams: Definem load balancing e health checks

Estrutura do Projeto

kong-gateway/
├── docker/
│   ├── docker-compose.yml
│   ├── docker-compose.dev.yml
│   └── docker-compose.prod.yml
│
├── kong/
│   ├── kong.yml                    # Configuração declarativa
│   ├── kong.conf                   # Configuração do Kong
│   │
│   ├── plugins/                    # Plugins customizados
│   │   └── custom-auth/
│   │       ├── handler.lua
│   │       └── schema.lua
│   │
│   └── templates/                  # Templates de configuração
│       └── nginx.conf
│
├── config/
│   ├── services/                   # Definição dos services
│   │   ├── user-service.yml
│   │   ├── order-service.yml
│   │   └── product-service.yml
│   │
│   ├── routes/                     # Definição das routes
│   │   ├── user-routes.yml
│   │   ├── order-routes.yml
│   │   └── product-routes.yml
│   │
│   ├── plugins/                    # Configuração de plugins
│   │   ├── global-plugins.yml
│   │   ├── auth-plugins.yml
│   │   └── rate-limiting.yml
│   │
│   └── consumers/                  # Definição de consumers
│       ├── mobile-app.yml
│       ├── web-app.yml
│       └── partners.yml
│
├── scripts/
│   ├── setup.sh                    # Script de setup inicial
│   ├── deploy.sh                   # Script de deploy
│   ├── backup.sh                   # Backup de configurações
│   └── health-check.sh             # Health check dos services
│
├── k8s/
│   ├── namespace.yaml
│   ├── kong-deployment.yaml
│   ├── kong-service.yaml
│   ├── kong-ingress.yaml
│   ├── configmap.yaml
│   └── secrets.yaml
│
├── monitoring/
│   ├── prometheus/
│   │   └── kong-metrics.yml
│   └── grafana/
│       └── kong-dashboard.json
│
├── tests/
│   ├── integration/
│   │   ├── auth.test.js
│   │   ├── rate-limiting.test.js
│   │   └── routing.test.js
│   └── load/
│       └── k6-load-test.js
│
├── Makefile
└── README.md

Instalação e Configuração

Docker Compose (Desenvolvimento)

yaml
# docker/docker-compose.ymlversion: '3.8' services:  kong-database:    image: postgres:15-alpine    container_name: kong-database    environment:      POSTGRES_USER: kong      POSTGRES_PASSWORD: kongpass      POSTGRES_DB: kong    volumes:      - kong_data:/var/lib/postgresql/data    healthcheck:      test: ["CMD-SHELL", "pg_isready -U kong"]      interval: 5s      timeout: 5s      retries: 5    networks:      - kong-net   kong-migrations:    image: kong:3.5-alpine    container_name: kong-migrations    command: kong migrations bootstrap    depends_on:      kong-database:        condition: service_healthy    environment:      KONG_DATABASE: postgres      KONG_PG_HOST: kong-database      KONG_PG_USER: kong      KONG_PG_PASSWORD: kongpass      KONG_PG_DATABASE: kong    networks:      - kong-net    restart: on-failure   kong:    image: kong:3.5-alpine    container_name: kong    depends_on:      kong-migrations:        condition: service_completed_successfully    environment:      KONG_DATABASE: postgres      KONG_PG_HOST: kong-database      KONG_PG_USER: kong      KONG_PG_PASSWORD: kongpass      KONG_PG_DATABASE: kong      KONG_PROXY_ACCESS_LOG: /dev/stdout      KONG_ADMIN_ACCESS_LOG: /dev/stdout      KONG_PROXY_ERROR_LOG: /dev/stderr      KONG_ADMIN_ERROR_LOG: /dev/stderr      KONG_ADMIN_LISTEN: 0.0.0.0:8001, 0.0.0.0:8444 ssl      KONG_PROXY_LISTEN: 0.0.0.0:8000, 0.0.0.0:8443 ssl      KONG_LOG_LEVEL: info      KONG_PLUGINS: bundled,custom-auth    ports:      - "8000:8000"   # Proxy HTTP      - "8443:8443"   # Proxy HTTPS      - "8001:8001"   # Admin API HTTP      - "8444:8444"   # Admin API HTTPS    healthcheck:      test: ["CMD", "kong", "health"]      interval: 10s      timeout: 10s      retries: 10    networks:      - kong-net    restart: unless-stopped   konga:    image: pantsel/konga:latest    container_name: konga    depends_on:      - kong    environment:      NODE_ENV: production      TOKEN_SECRET: your-secret-token    ports:      - "1337:1337"    networks:      - kong-net volumes:  kong_data: networks:  kong-net:    driver: bridge

Configuração Declarativa (DB-less)

yaml
# kong/kong.yml_format_version: "3.0"_transform: true # ===========================================# SERVICES# ===========================================services:  # User Service  - name: user-service    url: http://user-service:3000    connect_timeout: 5000    write_timeout: 60000    read_timeout: 60000    retries: 3    tags:      - internal      - users   # Order Service  - name: order-service    url: http://order-service:3001    connect_timeout: 5000    write_timeout: 60000    read_timeout: 60000    retries: 3    tags:      - internal      - orders   # Product Service  - name: product-service    url: http://product-service:3002    connect_timeout: 5000    write_timeout: 60000    read_timeout: 60000    retries: 3    tags:      - internal      - products # ===========================================# ROUTES# ===========================================routes:  # User Routes  - name: user-api    service: user-service    paths:      - /api/v1/users    methods:      - GET      - POST      - PUT      - DELETE      - PATCH    strip_path: false    preserve_host: true    tags:      - public   - name: user-auth    service: user-service    paths:      - /api/v1/auth    methods:      - POST    strip_path: false    tags:      - public      - auth   # Order Routes  - name: order-api    service: order-service    paths:      - /api/v1/orders    methods:      - GET      - POST      - PUT      - DELETE    strip_path: false    preserve_host: true    tags:      - public   # Product Routes  - name: product-api    service: product-service    paths:      - /api/v1/products    methods:      - GET      - POST      - PUT      - DELETE    strip_path: false    preserve_host: true    tags:      - public # ===========================================# UPSTREAMS (Load Balancing)# ===========================================upstreams:  - name: user-service-upstream    algorithm: round-robin    healthchecks:      active:        healthy:          interval: 5          successes: 2        unhealthy:          interval: 5          http_failures: 3        http_path: /health/live        timeout: 3      passive:        healthy:          successes: 2        unhealthy:          http_failures: 3    targets:      - target: user-service-1:3000        weight: 100      - target: user-service-2:3000        weight: 100      - target: user-service-3:3000        weight: 100 # ===========================================# CONSUMERS# ===========================================consumers:  - username: mobile-app    custom_id: mobile-app-001    tags:      - mobile      - external   - username: web-app    custom_id: web-app-001    tags:      - web      - internal   - username: partner-api    custom_id: partner-001    tags:      - partner      - external # ===========================================# PLUGINS (Global)# ===========================================plugins:  # Correlation ID para tracing  - name: correlation-id    config:      header_name: X-Correlation-ID      generator: uuid      echo_downstream: true   # Logging  - name: file-log    config:      path: /var/log/kong/requests.log      reopen: true   # CORS  - name: cors    config:      origins:        - "https://app.example.com"        - "https://admin.example.com"      methods:        - GET        - POST        - PUT        - DELETE        - PATCH        - OPTIONS      headers:        - Accept        - Authorization        - Content-Type        - X-Correlation-ID      exposed_headers:        - X-Correlation-ID      credentials: true      max_age: 3600   # Response Transformer  - name: response-transformer    config:      add:        headers:          - "X-Powered-By:Kong"          - "X-Response-Time:${latency}"

Implementação de Plugins

1. Autenticação JWT

yaml
# config/plugins/auth-plugins.ymlplugins:  # JWT Authentication (Global para rotas protegidas)  - name: jwt    route: user-api    config:      key_claim_name: kid      claims_to_verify:        - exp      header_names:        - Authorization      uri_param_names:        - jwt      cookie_names: []      maximum_expiration: 86400      run_on_preflight: true   # API Key para partners  - name: key-auth    route: partner-api    config:      key_names:        - X-API-Key        - apikey      key_in_header: true      key_in_query: true      key_in_body: false      hide_credentials: true

Configurando JWT no Kong

bash
# Criar consumercurl -X POST http://localhost:8001/consumers \  -d "username=mobile-app" \  -d "custom_id=mobile-001" # Criar credencial JWT para o consumercurl -X POST http://localhost:8001/consumers/mobile-app/jwt \  -d "algorithm=RS256" \  -d "key=mobile-app-key" \  -d "rsa_public_key=@/path/to/public_key.pem"

2. Rate Limiting Avançado

yaml
# config/plugins/rate-limiting.ymlplugins:  # Rate Limiting Global  - name: rate-limiting-advanced    config:      limit:        - 1000    # requests      window_size:        - 60      # seconds      window_type: sliding      sync_rate: 10      strategy: redis      redis:        host: redis        port: 6379        database: 0        timeout: 2000      hide_client_headers: false      identifier: consumer      header_name: X-Consumer-Username   # Rate Limiting por Rota (mais restritivo para auth)  - name: rate-limiting    route: user-auth    config:      minute: 10      hour: 100      policy: redis      redis_host: redis      redis_port: 6379      fault_tolerant: true      hide_client_headers: false   # Rate Limiting por Consumer (Partner com limite maior)  - name: rate-limiting    consumer: partner-api    config:      minute: 5000      hour: 100000      policy: redis      redis_host: redis

3. Request/Response Transformation

yaml
# config/plugins/transformations.ymlplugins:  # Request Transformer  - name: request-transformer    route: user-api    config:      add:        headers:          - "X-Gateway-Version:1.0"          - "X-Request-Start:$(now)"        querystring:          - "gateway:kong"      remove:        headers:          - "X-Internal-Header"      rename:        headers:          - "X-Old-Header:X-New-Header"   # Response Transformer  - name: response-transformer    route: user-api    config:      add:        headers:          - "X-Response-Time:${latency}ms"          - "X-Kong-Upstream-Status:${upstream_status}"      remove:        headers:          - "X-Powered-By"          - "Server"

4. Circuit Breaker

lua
-- kong/plugins/circuit-breaker/handler.lualocal CircuitBreakerHandler = {  VERSION = "1.0.0",  PRIORITY = 900,} local CLOSED = "CLOSED"local OPEN = "OPEN"local HALF_OPEN = "HALF_OPEN" local function get_circuit_state(conf, service_id)  local cache_key = "circuit:" .. service_id  local state = kong.cache:get(cache_key)  return state or {    status = CLOSED,    failures = 0,    last_failure = 0  }end local function set_circuit_state(conf, service_id, state)  local cache_key = "circuit:" .. service_id  kong.cache:set(cache_key, state, conf.state_ttl)end function CircuitBreakerHandler:access(conf)  local service_id = kong.router.get_service().id  local state = get_circuit_state(conf, service_id)   if state.status == OPEN then    local now = ngx.now()    if now - state.last_failure > conf.reset_timeout then      state.status = HALF_OPEN      state.failures = 0      set_circuit_state(conf, service_id, state)    else      return kong.response.exit(503, {        message = "Service temporarily unavailable",        circuit_state = OPEN,        retry_after = conf.reset_timeout - (now - state.last_failure)      })    end  endend function CircuitBreakerHandler:response(conf)  local service_id = kong.router.get_service().id  local state = get_circuit_state(conf, service_id)  local status = kong.response.get_status()   if status >= 500 then    state.failures = state.failures + 1    state.last_failure = ngx.now()     if state.failures >= conf.failure_threshold then      state.status = OPEN      kong.log.warn("Circuit breaker OPEN for service: ", service_id)    end  else    if state.status == HALF_OPEN then      state.status = CLOSED      kong.log.info("Circuit breaker CLOSED for service: ", service_id)    end    state.failures = 0  end   set_circuit_state(conf, service_id, state)end return CircuitBreakerHandler
lua
-- kong/plugins/circuit-breaker/schema.lualocal typedefs = require "kong.db.schema.typedefs" return {  name = "circuit-breaker",  fields = {    { consumer = typedefs.no_consumer },    { protocols = typedefs.protocols_http },    { config = {        type = "record",        fields = {          { failure_threshold = {              type = "integer",              default = 5,              gt = 0          }},          { reset_timeout = {              type = "integer",              default = 30,              gt = 0          }},          { state_ttl = {              type = "integer",              default = 300,              gt = 0          }},        },      },    },  },}

Autenticação e Autorização

OAuth 2.0 / OpenID Connect

yaml
# config/plugins/oidc.ymlplugins:  - name: openid-connect    route: user-api    config:      issuer: https://auth.example.com/.well-known/openid-configuration      client_id: kong-gateway      client_secret: ${OIDC_CLIENT_SECRET}      redirect_uri: https://api.example.com/callback      scopes:        - openid        - profile        - email      auth_methods:        - authorization_code        - client_credentials      consumer_claim:        - sub      consumer_by:        - username        - custom_id      verify_claims:        - exp        - iss      cache_ttl: 3600      cache_introspection: true

RBAC (Role-Based Access Control)

typescript
// Middleware de RBAC no seu microserviçointerface JWTPayload {  sub: string;  roles: string[];  permissions: string[];  exp: number;} export function requireRoles(...requiredRoles: string[]) {  return (req: Request, res: Response, next: NextFunction) => {    const token = req.headers['x-consumer-custom-id'];    const roles = req.headers['x-consumer-roles']?.split(',') || [];     const hasRole = requiredRoles.some(role => roles.includes(role));     if (!hasRole) {      return res.status(403).json({        error: 'Forbidden',        message: 'Insufficient permissions',        required: requiredRoles,        current: roles,      });    }     next();  };} // Uso no controllerapp.get('/api/v1/users',  requireRoles('admin', 'user-manager'),  userController.list);

Observabilidade

Prometheus Metrics

yaml
# config/plugins/prometheus.ymlplugins:  - name: prometheus    config:      per_consumer: true      status_code_metrics: true      latency_metrics: true      bandwidth_metrics: true      upstream_health_metrics: true

Configuração do Prometheus

yaml
# monitoring/prometheus/prometheus.ymlglobal:  scrape_interval: 15s  evaluation_interval: 15s scrape_configs:  - job_name: 'kong'    static_configs:      - targets: ['kong:8001']    metrics_path: /metrics   - job_name: 'kong-services'    static_configs:      - targets:          - 'user-service:3000'          - 'order-service:3001'          - 'product-service:3002'    metrics_path: /metrics alerting:  alertmanagers:    - static_configs:        - targets: ['alertmanager:9093'] rule_files:  - '/etc/prometheus/rules/*.yml'

Alertas

yaml
# monitoring/prometheus/rules/kong-alerts.ymlgroups:  - name: kong-alerts    rules:      - alert: KongHighLatency        expr: histogram_quantile(0.95, rate(kong_latency_bucket[5m])) > 1000        for: 5m        labels:          severity: warning        annotations:          summary: "High latency detected on Kong"          description: "95th percentile latency is above 1s"       - alert: KongHighErrorRate        expr: |          sum(rate(kong_http_requests_total{code=~"5.."}[5m]))          /          sum(rate(kong_http_requests_total[5m])) > 0.05        for: 5m        labels:          severity: critical        annotations:          summary: "High error rate on Kong"          description: "Error rate is above 5%"       - alert: KongUpstreamDown        expr: kong_upstream_target_health == 0        for: 1m        labels:          severity: critical        annotations:          summary: "Kong upstream target is down"          description: "{{ $labels.upstream }} target {{ $labels.target }} is unhealthy"       - alert: KongRateLimitExceeded        expr: increase(kong_http_requests_total{code="429"}[5m]) > 100        for: 5m        labels:          severity: warning        annotations:          summary: "High rate limit exceeded count"          description: "Many requests are being rate limited"

Dashboard Grafana

json
{  "dashboard": {    "title": "Kong API Gateway",    "panels": [      {        "title": "Requests per Second",        "type": "graph",        "targets": [          {            "expr": "sum(rate(kong_http_requests_total[1m])) by (service)",            "legendFormat": "{{service}}"          }        ]      },      {        "title": "Response Time (p95)",        "type": "graph",        "targets": [          {            "expr": "histogram_quantile(0.95, sum(rate(kong_latency_bucket[5m])) by (le, service))",            "legendFormat": "{{service}}"          }        ]      },      {        "title": "Error Rate",        "type": "graph",        "targets": [          {            "expr": "sum(rate(kong_http_requests_total{code=~\"5..\"}[5m])) by (service) / sum(rate(kong_http_requests_total[5m])) by (service) * 100",            "legendFormat": "{{service}}"          }        ]      },      {        "title": "Upstream Health",        "type": "stat",        "targets": [          {            "expr": "kong_upstream_target_health",            "legendFormat": "{{upstream}} - {{target}}"          }        ]      }    ]  }}

Distributed Tracing (Jaeger/Zipkin)

yaml
# config/plugins/tracing.ymlplugins:  - name: zipkin    config:      http_endpoint: http://jaeger:9411/api/v2/spans      sample_ratio: 1.0      include_credential: true      traceid_byte_count: 16      header_type: preserve      default_header_type: jaeger      tags_header: X-B3-Tags

Deploy em Kubernetes

Helm Chart

bash
# Adicionar repositório oficialhelm repo add kong https://charts.konghq.comhelm repo update # Instalar Konghelm install kong kong/kong \  --namespace kong \  --create-namespace \  --values values.yaml

Values.yaml Customizado

yaml
# k8s/helm/values.yamlimage:  repository: kong  tag: "3.5" env:  database: "off"  declarative_config: /kong/declarative/kong.yml   # Plugins  plugins: bundled,circuit-breaker   # Logging  proxy_access_log: /dev/stdout  admin_access_log: /dev/stdout  proxy_error_log: /dev/stderr  admin_error_log: /dev/stderr  log_level: info   # Metrics  status_listen: 0.0.0.0:8100 ingressController:  enabled: true  installCRDs: false proxy:  enabled: true  type: LoadBalancer  http:    enabled: true    containerPort: 8000    servicePort: 80  tls:    enabled: true    containerPort: 8443    servicePort: 443 admin:  enabled: true  type: ClusterIP  http:    enabled: true    containerPort: 8001    servicePort: 8001 status:  enabled: true  http:    enabled: true    containerPort: 8100    servicePort: 8100 secretVolumes:  - kong-declarative-config resources:  requests:    cpu: 500m    memory: 512Mi  limits:    cpu: 2000m    memory: 2Gi autoscaling:  enabled: true  minReplicas: 3  maxReplicas: 10  targetCPUUtilizationPercentage: 70 podDisruptionBudget:  enabled: true  minAvailable: 2 affinity:  podAntiAffinity:    preferredDuringSchedulingIgnoredDuringExecution:      - weight: 100        podAffinityTerm:          labelSelector:            matchLabels:              app.kubernetes.io/name: kong          topologyKey: kubernetes.io/hostname

Kong Ingress Controller

yaml
# k8s/kong-ingress.yamlapiVersion: networking.k8s.io/v1kind: Ingressmetadata:  name: api-ingress  annotations:    konghq.com/strip-path: "false"    konghq.com/plugins: rate-limiting,jwt-auth    cert-manager.io/cluster-issuer: letsencrypt-prodspec:  ingressClassName: kong  tls:    - hosts:        - api.example.com      secretName: api-tls  rules:    - host: api.example.com      http:        paths:          - path: /api/v1/users            pathType: Prefix            backend:              service:                name: user-service                port:                  number: 3000          - path: /api/v1/orders            pathType: Prefix            backend:              service:                name: order-service                port:                  number: 3001          - path: /api/v1/products            pathType: Prefix            backend:              service:                name: product-service                port:                  number: 3002

KongPlugin CRD

yaml
# k8s/plugins/rate-limiting.yamlapiVersion: configuration.konghq.com/v1kind: KongPluginmetadata:  name: rate-limiting  namespace: kongconfig:  minute: 1000  policy: redis  redis_host: redis.kong.svc.cluster.local  redis_port: 6379plugin: rate-limiting ---# k8s/plugins/jwt-auth.yamlapiVersion: configuration.konghq.com/v1kind: KongPluginmetadata:  name: jwt-auth  namespace: kongconfig:  key_claim_name: kid  claims_to_verify:    - expplugin: jwt

Testes

Testes de Integração

typescript
// tests/integration/kong.test.tsimport axios from 'axios'; const KONG_URL = process.env.KONG_URL || 'http://localhost:8000';const KONG_ADMIN = process.env.KONG_ADMIN || 'http://localhost:8001'; describe('Kong API Gateway', () => {  describe('Routing', () => {    it('should route requests to user service', async () => {      const response = await axios.get(`${KONG_URL}/api/v1/users`);       expect(response.status).toBe(200);      expect(response.headers['x-kong-upstream-latency']).toBeDefined();    });     it('should return 404 for unknown routes', async () => {      try {        await axios.get(`${KONG_URL}/api/v1/unknown`);      } catch (error: any) {        expect(error.response.status).toBe(404);      }    });  });   describe('Authentication', () => {    it('should reject requests without JWT', async () => {      try {        await axios.get(`${KONG_URL}/api/v1/users`, {          headers: { 'Authorization': '' }        });      } catch (error: any) {        expect(error.response.status).toBe(401);      }    });     it('should accept requests with valid JWT', async () => {      const token = await getValidJWT();       const response = await axios.get(`${KONG_URL}/api/v1/users`, {        headers: { 'Authorization': `Bearer ${token}` }      });       expect(response.status).toBe(200);    });  });   describe('Rate Limiting', () => {    it('should enforce rate limits', async () => {      const requests = Array(15).fill(null).map(() =>        axios.get(`${KONG_URL}/api/v1/auth/login`, {          validateStatus: () => true        })      );       const responses = await Promise.all(requests);      const rateLimited = responses.filter(r => r.status === 429);       expect(rateLimited.length).toBeGreaterThan(0);    });     it('should include rate limit headers', async () => {      const response = await axios.get(`${KONG_URL}/api/v1/users`);       expect(response.headers['x-ratelimit-limit-minute']).toBeDefined();      expect(response.headers['x-ratelimit-remaining-minute']).toBeDefined();    });  });   describe('Health Checks', () => {    it('should report healthy status', async () => {      const response = await axios.get(`${KONG_ADMIN}/status`);       expect(response.status).toBe(200);      expect(response.data.database.reachable).toBe(true);    });  });});

Testes de Carga (k6)

javascript
// tests/load/k6-load-test.jsimport http from 'k6/http';import { check, sleep } from 'k6';import { Rate, Trend } from 'k6/metrics'; const errorRate = new Rate('errors');const latencyTrend = new Trend('latency'); export const options = {  stages: [    { duration: '1m', target: 50 },   // Ramp-up    { duration: '5m', target: 100 },  // Sustain    { duration: '1m', target: 200 },  // Spike    { duration: '2m', target: 100 },  // Recovery    { duration: '1m', target: 0 },    // Ramp-down  ],  thresholds: {    http_req_duration: ['p(95)<500'],    errors: ['rate<0.01'],  },}; const BASE_URL = __ENV.KONG_URL || 'http://localhost:8000';const TOKEN = __ENV.JWT_TOKEN; export default function () {  const headers = {    'Authorization': `Bearer ${TOKEN}`,    'Content-Type': 'application/json',  };   // GET Users  const getUsers = http.get(`${BASE_URL}/api/v1/users`, { headers });  check(getUsers, {    'GET users status is 200': (r) => r.status === 200,    'GET users has data': (r) => r.json().data !== undefined,  });  errorRate.add(getUsers.status !== 200);  latencyTrend.add(getUsers.timings.duration);   sleep(1);   // POST User  const payload = JSON.stringify({    email: `user-${Date.now()}@test.com`,    password: 'Password123',    name: 'Test User',  });   const createUser = http.post(`${BASE_URL}/api/v1/users`, payload, { headers });  check(createUser, {    'POST user status is 201': (r) => r.status === 201,    'POST user has id': (r) => r.json().id !== undefined,  });  errorRate.add(createUser.status !== 201);  latencyTrend.add(createUser.timings.duration);   sleep(1);}

Checklist de Produção

Segurança

  • TLS/SSL configurado em todas as portas
  • Admin API protegida (não exposta publicamente)
  • Secrets gerenciados via Vault/K8s Secrets
  • Rate limiting habilitado
  • CORS configurado corretamente
  • Validação de input habilitada
  • Headers de segurança configurados

Performance

  • Connection pooling configurado
  • Timeouts ajustados por serviço
  • Cache habilitado onde apropriado
  • Compressão gzip habilitada
  • Keep-alive configurado

Resiliência

  • Health checks configurados
  • Circuit breaker implementado
  • Retry policies configuradas
  • Load balancing ativo
  • Failover configurado

Observabilidade

  • Métricas Prometheus expostas
  • Logs estruturados
  • Distributed tracing habilitado
  • Alertas configurados
  • Dashboards criados

Operacional

  • Backup de configurações automatizado
  • Runbook documentado
  • Processo de rollback definido
  • Disaster recovery testado

Conclusão

Um API Gateway bem implementado é fundamental para uma arquitetura de microserviços robusta. O Kong oferece uma base sólida com:

  1. Performance: Milhões de requests por segundo
  2. Flexibilidade: 100+ plugins e suporte a customização
  3. Observabilidade: Métricas, logs e tracing integrados
  4. Segurança: Autenticação, autorização e rate limiting
  5. Resiliência: Circuit breaker, retry e health checks

No próximo artigo, aprenda a implementar Mensageria com RabbitMQ para comunicação assíncrona entre microserviços.

PF
Sobre o autor

Pedro Farbo

Platform Engineering Lead & Solutions Architect com +10 anos de experiência. CEO da Farbo TSC. Especialista em Microserviços, Kong, Backstage e Cloud.

Gostou do conteúdo? Sua contribuição ajuda a manter tudo online e gratuito!

PIX:0737160d-e98f-4a65-8392-5dba70e7ff3e