API Gateway Pattern
API Gateway Pattern
Ein API Gateway ist der zentrale Einstiegspunkt für alle Client-Anfragen. Lernen Sie Routing, Authentifizierung und weitere Cross-Cutting Concerns zu implementieren.
Das Konzept
┌─────────────────────────────────────────────────────────────┐ │ API GATEWAY PATTERN │ ├─────────────────────────────────────────────────────────────┤ │ │ │ OHNE API GATEWAY: │ │ ┌─────────┐ │ │ │ Mobile │──┐ │ │ │ App │ │ ┌────────────────┐ │ │ └─────────┘ ├──►│ User Service │ │ │ ┌─────────┐ │ └────────────────┘ │ │ │ Web │──┤ ┌────────────────┐ │ │ │ App │ ├──►│ Order Service │ │ │ └─────────┘ │ └────────────────┘ │ │ ┌─────────┐ │ ┌────────────────┐ │ │ │ Partner │──┴──►│ Product Service│ │ │ │ API │ └────────────────┘ │ │ └─────────┘ │ │ × Jeder Client kennt alle Services │ │ × Jeder Service braucht Auth, Rate Limiting, etc. │ │ │ │ MIT API GATEWAY: │ │ ┌─────────┐ ┌─────────────┐ ┌────────────────┐ │ │ │ Mobile │ │ │ │ User Service │ │ │ │ App │─────►│ │──►└────────────────┘ │ │ └─────────┘ │ │ ┌────────────────┐ │ │ ┌─────────┐ │ API GATEWAY │──►│ Order Service │ │ │ │ Web │─────►│ │ └────────────────┘ │ │ │ App │ │ │ ┌────────────────┐ │ │ └─────────┘ │ │──►│ Product Service│ │ │ ┌─────────┐ │ │ └────────────────┘ │ │ │ Partner │─────►│ │ │ │ │ API │ └─────────────┘ │ │ └─────────┘ │ │ ✓ Zentraler Einstiegspunkt │ │ ✓ Cross-Cutting Concerns an einer Stelle │ │ │ └─────────────────────────────────────────────────────────────┘
API Gateway Funktionen
| Funktion | Beschreibung |
|---|---|
| Routing | Requests an richtige Services weiterleiten |
| Authentication | JWT/OAuth Token validieren |
| Authorization | Zugriffsrechte prüfen |
| Rate Limiting | Request-Limits durchsetzen |
| Load Balancing | Last auf Service-Instanzen verteilen |
| Caching | Responses zwischenspeichern |
| Request/Response Transformation | Formate konvertieren |
| Circuit Breaking | Fehlerhafte Services isolieren |
Kong Gateway Beispiel
# Kong Installation (Docker) docker network create kong-net # PostgreSQL für Kong docker run -d --name kong-database \ --network kong-net \ -e POSTGRES_USER=kong \ -e POSTGRES_DB=kong \ -e POSTGRES_PASSWORD=kong \ postgres:15 # Kong Migrations docker run --rm --network kong-net \ -e KONG_DATABASE=postgres \ -e KONG_PG_HOST=kong-database \ -e KONG_PG_PASSWORD=kong \ kong:latest kong migrations bootstrap # Kong starten docker run -d --name kong \ --network kong-net \ -e KONG_DATABASE=postgres \ -e KONG_PG_HOST=kong-database \ -e KONG_PG_PASSWORD=kong \ -e KONG_PROXY_ACCESS_LOG=/dev/stdout \ -e KONG_ADMIN_ACCESS_LOG=/dev/stdout \ -e KONG_PROXY_ERROR_LOG=/dev/stderr \ -e KONG_ADMIN_ERROR_LOG=/dev/stderr \ -e KONG_ADMIN_LISTEN=0.0.0.0:8001 \ -p 8000:8000 \ -p 8001:8001 \ kong:latest
# Services und Routes konfigurieren # Service hinzufügen curl -X POST http://localhost:8001/services \ --data name=user-service \ --data url=http://user-service:8080 # Route hinzufügen curl -X POST http://localhost:8001/services/user-service/routes \ --data paths[]=/api/users \ --data strip_path=true # JWT Plugin aktivieren curl -X POST http://localhost:8001/services/user-service/plugins \ --data name=jwt # Rate Limiting curl -X POST http://localhost:8001/services/user-service/plugins \ --data name=rate-limiting \ --data config.second=5 \ --data config.minute=100 \ --data config.hour=1000 # Request wird jetzt geroutet: # GET http://gateway:8000/api/users # → http://user-service:8080/
NGINX als API Gateway
# nginx.conf
upstream user_service {
server user-service-1:8080;
server user-service-2:8080;
}
upstream order_service {
server order-service-1:8080;
}
# Rate Limiting Zone
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
server {
listen 80;
server_name api.example.com;
# Global Rate Limiting
limit_req zone=api_limit burst=20 nodelay;
# JWT Validation (mit nginx-jwt Modul)
# auth_jwt "API" token=$http_authorization;
# auth_jwt_key_file /etc/nginx/jwt.key;
# User Service
location /api/users {
proxy_pass http://user_service;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Request-ID $request_id;
# Circuit Breaker
proxy_connect_timeout 5s;
proxy_read_timeout 30s;
proxy_next_upstream error timeout http_502 http_503;
}
# Order Service
location /api/orders {
proxy_pass http://order_service;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# Health Check Endpoint
location /health {
return 200 '{"status":"ok"}';
add_header Content-Type application/json;
}
# Caching für GET Requests
location /api/products {
proxy_pass http://product_service;
proxy_cache api_cache;
proxy_cache_valid 200 10m;
proxy_cache_key $scheme$request_method$host$request_uri;
}
}
AWS API Gateway
# Terraform Beispiel
resource "aws_api_gateway_rest_api" "api" {
name = "my-api"
description = "API Gateway"
}
# User Resource
resource "aws_api_gateway_resource" "users" {
rest_api_id = aws_api_gateway_rest_api.api.id
parent_id = aws_api_gateway_rest_api.api.root_resource_id
path_part = "users"
}
# GET /users
resource "aws_api_gateway_method" "get_users" {
rest_api_id = aws_api_gateway_rest_api.api.id
resource_id = aws_api_gateway_resource.users.id
http_method = "GET"
authorization = "COGNITO_USER_POOLS"
authorizer_id = aws_api_gateway_authorizer.cognito.id
}
# Lambda Integration
resource "aws_api_gateway_integration" "get_users" {
rest_api_id = aws_api_gateway_rest_api.api.id
resource_id = aws_api_gateway_resource.users.id
http_method = aws_api_gateway_method.get_users.http_method
integration_http_method = "POST"
type = "AWS_PROXY"
uri = aws_lambda_function.get_users.invoke_arn
}
# Cognito Authorizer
resource "aws_api_gateway_authorizer" "cognito" {
name = "cognito-authorizer"
rest_api_id = aws_api_gateway_rest_api.api.id
type = "COGNITO_USER_POOLS"
provider_arns = [aws_cognito_user_pool.main.arn]
}
# Usage Plan (Rate Limiting)
resource "aws_api_gateway_usage_plan" "basic" {
name = "basic-plan"
api_stages {
api_id = aws_api_gateway_rest_api.api.id
stage = aws_api_gateway_stage.prod.stage_name
}
throttle_settings {
burst_limit = 100
rate_limit = 50
}
quota_settings {
limit = 10000
period = "MONTH"
}
}
Express.js API Gateway
// Einfaches API Gateway mit Node.js
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const rateLimit = require('express-rate-limit');
const jwt = require('express-jwt');
const app = express();
// Rate Limiting
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 Minuten
max: 100, // 100 Requests pro Window
message: { error: 'Too many requests' }
});
app.use(limiter);
// JWT Validation
const jwtMiddleware = jwt({
secret: process.env.JWT_SECRET,
algorithms: ['HS256'],
credentialsRequired: true
}).unless({
path: ['/health', '/api/auth/login']
});
app.use(jwtMiddleware);
// Request Logging
app.use((req, res, next) => {
req.requestId = require('uuid').v4();
console.log(`[${req.requestId}] ${req.method} ${req.path}`);
next();
});
// Service Proxies
app.use('/api/users', createProxyMiddleware({
target: process.env.USER_SERVICE_URL,
changeOrigin: true,
pathRewrite: { '^/api/users': '' },
onProxyReq: (proxyReq, req) => {
proxyReq.setHeader('X-Request-ID', req.requestId);
proxyReq.setHeader('X-User-ID', req.user?.sub);
}
}));
app.use('/api/orders', createProxyMiddleware({
target: process.env.ORDER_SERVICE_URL,
changeOrigin: true,
pathRewrite: { '^/api/orders': '' }
}));
// Health Check
app.get('/health', (req, res) => {
res.json({ status: 'ok' });
});
// Error Handler
app.use((err, req, res, next) => {
if (err.name === 'UnauthorizedError') {
return res.status(401).json({ error: 'Invalid token' });
}
console.error(err);
res.status(500).json({ error: 'Internal server error' });
});
app.listen(3000);
BFF Pattern (Backend for Frontend)
┌─────────────────────────────────────────────────────────────┐ │ BACKEND FOR FRONTEND (BFF) │ ├─────────────────────────────────────────────────────────────┤ │ │ │ Jeder Client bekommt eigenes Gateway/BFF: │ │ │ │ ┌──────────┐ ┌────────────┐ │ │ │ Mobile │─────►│ Mobile BFF │──┐ │ │ │ App │ └────────────┘ │ │ │ └──────────┘ │ ┌──────────────┐ │ │ ├──►│ User Service │ │ │ ┌──────────┐ ┌────────────┐ │ └──────────────┘ │ │ │ Web │─────►│ Web BFF │──┤ │ │ │ App │ └────────────┘ │ ┌──────────────┐ │ │ └──────────┘ ├──►│Order Service │ │ │ │ └──────────────┘ │ │ ┌──────────┐ ┌────────────┐ │ │ │ │ Admin │─────►│ Admin BFF │──┘ │ │ │ Portal │ └────────────┘ │ │ └──────────┘ │ │ │ │ VORTEILE: │ │ • Optimierte Responses pro Client │ │ • Mobile: Weniger Daten, aggregierte Calls │ │ • Web: Mehr Daten, komplexere Strukturen │ │ • Admin: Spezielle Endpoints │ │ │ └─────────────────────────────────────────────────────────────┘
Gateway vs Service Mesh
API GATEWAY • Extern → Intern (North-South Traffic) • Edge-Fokus • Client-facing Features • Zentral deployed SERVICE MESH (z.B. Istio) • Intern → Intern (East-West Traffic) • Service-to-Service Kommunikation • mTLS zwischen Services • Sidecar-basiert → Beide ergänzen sich oft! Gateway für externe Clients Service Mesh für interne Kommunikation
💡 Best Practices:
1. Keine Business-Logik im Gateway
2. Gateway als Single Point of Failure vermeiden (HA)
3. Timeouts und Circuit Breakers konfigurieren
4. Request IDs für Tracing durchreichen
5. BFF für unterschiedliche Client-Bedürfnisse
2. Gateway als Single Point of Failure vermeiden (HA)
3. Timeouts und Circuit Breakers konfigurieren
4. Request IDs für Tracing durchreichen
5. BFF für unterschiedliche Client-Bedürfnisse