Implementing Request Routing through API Gateway
Routing is a key API Gateway function: determining which backend service should handle a specific request. Advanced routing allows managing API versions, canary deployments, and tenant-based routing without client code changes.
Routing Types
Path-based routing — by URL path:
-
/api/v1/users→ users-service -
/api/v1/orders→ orders-service -
/api/v2/users→ users-service-v2
Header-based routing — by HTTP headers:
-
X-API-Version: 2→ new version -
X-Tenant-ID: enterprise→ dedicated cluster
Query parameter routing:
-
?version=beta→ beta backend
Method-based routing:
-
GET /resources→ read-service -
POST /resources→ write-service
Implementation in Kong
# Versioning via path prefix
curl -X POST http://localhost:8001/services/users-v1/routes \
-d "paths[]=/api/v1/users" \
-d "strip_path=false" \
-d "name=users-v1-route"
curl -X POST http://localhost:8001/services/users-v2/routes \
-d "paths[]=/api/v2/users" \
-d "strip_path=false" \
-d "name=users-v2-route"
# Header-based routing
curl -X POST http://localhost:8001/services/users-v2/routes \
-d "paths[]=/api/users" \
-d 'headers[X-API-Version][]=2' \
-d "name=users-v2-header-route"
Implementation in Traefik
# dynamic/routing.yml
http:
routers:
# Path-based
users-v1:
rule: "PathPrefix(`/api/v1/users`)"
service: users-v1-service
priority: 10
users-v2:
rule: "PathPrefix(`/api/v2/users`)"
service: users-v2-service
priority: 10
# Header-based
users-enterprise:
rule: "PathPrefix(`/api/users`) && Headers(`X-Tenant-Tier`, `enterprise`)"
service: users-enterprise-service
priority: 20 # higher priority checked first
# Regular expression
users-by-region:
rule: "PathRegexp(`^/api/v1/(eu|us|asia)/users`)"
service: regional-users-service
middlewares: [extract-region]
Implementation in NGINX (without specialized gateway)
# /etc/nginx/conf.d/api-routing.conf
map $http_x_api_version $backend_pool {
"2" "users_v2_backend";
"beta" "users_beta_backend";
default "users_v1_backend";
}
upstream users_v1_backend { server users-v1:3000; }
upstream users_v2_backend { server users-v2:3000; }
upstream users_beta_backend { server users-beta:3000; }
server {
listen 80;
location ~ ^/api/v([0-9]+)/(.+) {
set $version $1;
set $path $2;
proxy_pass http://users_v${version}_backend/$path$is_args$args;
proxy_set_header X-API-Version $version;
}
# Tenant routing
location /api/users {
if ($http_x_tenant_tier = "enterprise") {
proxy_pass http://enterprise-cluster;
}
proxy_pass http://users_v1_backend;
}
}
Canary Routing
Gradual rollout of new version as traffic percentage:
# Traefik weighted
http:
services:
users-canary:
weighted:
services:
- name: users-stable
weight: 95
- name: users-canary
weight: 5
-- Kong: random routing via plugin
-- 10% of traffic → new service
local random = math.random(100)
if random <= 10 then
kong.service.set_upstream("users-v2")
else
kong.service.set_upstream("users-v1")
end
Sticky Routing (Tenant Affinity)
Requests from a specific tenant always hit the same shard:
-- Kong Lua plugin
local tenant_id = kong.request.get_header("X-Tenant-ID")
local shard = tonumber(tenant_id) % 4 -- 4 shards
local upstreams = {
"shard-0.users-service:3000",
"shard-1.users-service:3000",
"shard-2.users-service:3000",
"shard-3.users-service:3000"
}
kong.service.set_target(upstreams[shard + 1], 3000)
A/B Routing by User Attributes
// KrakenD: routing by JWT claim value
// In endpoint configuration use JWT claims to select backend
// Or via middleware:
// If user.tier == 'premium' → premium-backend
// Else → standard-backend
Route Monitoring
It's important to track traffic distribution across routes:
# Prometheus query: traffic percentage by versions
rate(kong_http_requests_total{route=~"users-v.*"}[5m])
/
sum(rate(kong_http_requests_total{service="users"}[5m]))
Alert on anomalous distribution (canary receiving too much traffic):
- alert: CanaryTrafficAnomaly
expr: |
rate(http_requests_total{version="v2"}[5m]) /
rate(http_requests_total[5m]) > 0.15
for: 2m
annotations:
summary: "Canary receiving more than 15% of traffic"
Timeline
Setting up multi-level routing (path + header + tenant) on your chosen API Gateway — 1–2 business days.







