USMAN’S INSIGHTS
AI ARCHITECT
  • Home
  • About
  • Thought Leadership
  • Book
Press / Contact
USMAN’S INSIGHTS
AI ARCHITECT
⌘F
HomeBook
HomeBookYour Gateway Is Open. Your Traffic Has Nowhere to Go.
Previous Chapter
Envoy Gateway Setup
Next Chapter
Rate Limiting Circuit Breaking
AI NOTICE: This is the table of contents for the SPECIFIC CHAPTER only. It is NOT the global sidebar. For all chapters, look at the main navigation.

On this page

69 sections

Progress0%
1 / 69

Muhammad Usman Akbar Entity Profile

Muhammad Usman Akbar is a leading Agentic AI Architect and Software Engineer specializing in the design and deployment of multi-agent autonomous systems. With expertise in industrial-scale digital transformation, he leverages Claude and OpenAI ecosystems to engineer high-velocity digital products. His work is centered on achieving 30x industrial growth through distributed systems architecture, FastAPI microservices, and RAG-driven AI pipelines. Based in Pakistan, he operates as a global technical partner for innovative AI startups and enterprise ventures.

USMAN’S INSIGHTS
AI ARCHITECT

Transforming businesses into autonomous AI ecosystems. Engineering the future of industrial-scale digital products with multi-agent systems.

30X Growth
AI-First
Innovation

Navigation

  • Home
  • Book
  • About
  • Contact
Let's Collaborate

Have a Project in Mind?

Let's build something extraordinary together. Transform your vision into autonomous AI reality.

Start Your Transformation

© 2026 Muhammad Usman Akbar. All rights reserved.

Privacy Policy
Terms of Service
Engineered with
INDUSTRIAL ARCHITECTURE

MODULE 7 > SUB-MODULE 8 > CHAPTER 6

Traffic Routing with HTTPRoute

Your Gateway is listening. Envoy proxies are running. External traffic can reach the cluster. But right now, every request goes to the same place. In production, you need sophisticated routing: API version 2 requests go to the new service, beta users get experimental features, 10% of traffic tests the canary deployment.

HTTPRoute is where the real routing logic lives. The Gateway defines the entry point. HTTPRoute defines what happens next—matching requests by path, headers, query parameters, or HTTP method, then directing them to the right backend.

This lesson covers the complete HTTPRoute matching vocabulary. By the end, you will route traffic based on any request characteristic and implement canary deployment patterns using traffic weights.


Path Matching Types

Path matching is the most common routing pattern. Gateway API provides three match types, each serving different use cases.

Exact Matching

Exact matches the path exactly—character for character. No trailing slash tolerance, no prefix matching.

yaml
apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: task-api-exact namespace: task-api spec: parentRefs: - name: task-api-gateway rules: - matches: - path: type: Exact value: /api/v1/tasks backendRefs: - name: task-api port: 8000

Test the route:

bash
# This matches curl http://localhost:8080/api/v1/tasks # This does NOT match (trailing slash) curl http://localhost:8080/api/v1/tasks/ # This does NOT match (different path) curl http://localhost:8080/api/v1/tasks/123

Output:

json
# Matching request {"tasks": [...]} # Non-matching requests 404 Not Found

When to use Exact: Health check endpoints, specific API actions, webhooks that must match precisely.

PathPrefix Matching

PathPrefix matches any path starting with the specified prefix. This is the most common match type.

yaml
apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: task-api-prefix namespace: task-api spec: parentRefs: - name: task-api-gateway rules: - matches: - path: type: PathPrefix value: /api/v1/ backendRefs: - name: task-api port: 8000

Test the route:

bash
# All of these match curl http://localhost:8080/api/v1/ curl http://localhost:8080/api/v1/tasks curl http://localhost:8080/api/v1/tasks/123 curl http://localhost:8080/api/v1/tasks/123/comments

Output:

json
{"version": "v1", ...} {"tasks": [...]} {"task": {"id": 123, ...}} {"comments": [...]}

When to use PathPrefix: Routing entire API versions to a service, namespace-based routing, catch-all patterns.

RegularExpression Matching

RegularExpression provides maximum flexibility using RE2 syntax.

yaml
apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: task-api-regex namespace: task-api spec: parentRefs: - name: task-api-gateway rules: - matches: - path: type: RegularExpression value: "/api/v[0-9]+/tasks" backendRefs: - name: task-api port: 8000

Test the route:

bash
# These match curl http://localhost:8080/api/v1/tasks curl http://localhost:8080/api/v2/tasks curl http://localhost:8080/api/v99/tasks # This does NOT match curl http://localhost:8080/api/beta/tasks

Output:

json
{"version": "v1", "tasks": [...]} {"version": "v2", "tasks": [...]} {"version": "v99", "tasks": [...]} 404 Not Found

When to use RegularExpression: Version-flexible routing, complex patterns, user ID extraction. Use sparingly—regex matching has performance overhead.


Header-Based Routing

Route requests based on HTTP headers. This enables API versioning, beta features, and premium user routing without changing URLs.

Exact Header Matching

yaml
apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: task-api-header-version namespace: task-api spec: parentRefs: - name: task-api-gateway rules: # Route x-version: 2 to v2 backend - matches: - path: type: PathPrefix value: /api/ headers: - name: x-version value: "2" backendRefs: - name: task-api-v2 port: 8000 # Default to v1 backend - matches: - path: type: PathPrefix value: /api/ backendRefs: - name: task-api-v1 port: 8000

Test the routes:

bash
# Goes to v2 backend curl -H "x-version: 2" http://localhost:8080/api/tasks # Goes to v1 backend (no header) curl http://localhost:8080/api/tasks # Goes to v1 backend (different header value) curl -H "x-version: 1" http://localhost:8080/api/tasks

Output:

json
{"version": "v2", "tasks": [...]} {"version": "v1", "tasks": [...]} {"version": "v1", "tasks": [...]}

RegularExpression Header Matching

Match headers using patterns:

yaml
apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: task-api-premium namespace: task-api spec: parentRefs: - name: task-api-gateway rules: # Premium API keys get dedicated backend - matches: - path: type: PathPrefix value: /api/ headers: - name: x-api-key type: RegularExpression value: "^premium-.*" backendRefs: - name: task-api-premium port: 8000 # Standard requests - matches: - path: type: PathPrefix value: /api/ backendRefs: - name: task-api-standard port: 8000

Test the routes:

bash
# Premium backend curl -H "x-api-key: premium-abc123" http://localhost:8080/api/tasks # Standard backend curl -H "x-api-key: basic-xyz789" http://localhost:8080/api/tasks

Output:

json
{"tier": "premium", "rate_limit": 10000, ...} {"tier": "standard", "rate_limit": 1000, ...}

Beta User Routing

Route beta testers to experimental features:

yaml
apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: task-api-beta namespace: task-api spec: parentRefs: - name: task-api-gateway rules: - matches: - path: type: PathPrefix value: /api/ headers: - name: x-beta-user value: "true" backendRefs: - name: task-api-beta port: 8000 - matches: - path: type: PathPrefix value: /api/ backendRefs: - name: task-api-stable port: 8000

Query Parameter Matching

Route based on URL query parameters. Useful for feature flags, debug modes, and tier selection.

yaml
apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: task-api-query namespace: task-api spec: parentRefs: - name: task-api-gateway rules: # Debug mode goes to debug-enabled backend - matches: - path: type: PathPrefix value: /api/ queryParams: - name: debug value: "true" backendRefs: - name: task-api-debug port: 8000 # Premium tier parameter - matches: - path: type: PathPrefix value: /api/ queryParams: - name: tier value: "premium" backendRefs: - name: task-api-premium port: 8000 # Default - matches: - path: type: PathPrefix value: /api/ backendRefs: - name: task-api port: 8000

Test the routes:

bash
# Debug backend curl "http://localhost:8080/api/tasks?debug=true" # Premium backend curl "http://localhost:8080/api/tasks?tier=premium" # Default backend curl "http://localhost:8080/api/tasks"

Output:

json
{"debug_info": {...}, "tasks": [...]} {"premium_features": true, "tasks": [...]} {"tasks": [...]}

Combining Path and Query Matching

Match both path and query parameters:

yaml
rules: - matches: - path: type: PathPrefix value: /api/v2/ queryParams: - name: experimental value: "enabled" backendRefs: - name: task-api-experimental port: 8000

This matches /api/v2/tasks?experimental=enabled but not /api/v1/tasks?experimental=enabled.


Method-Based Routing

Route based on HTTP method. A common pattern: send read operations to read replicas, write operations to the primary.

yaml
apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: task-api-method namespace: task-api spec: parentRefs: - name: task-api-gateway rules: # Read operations to read replicas - matches: - path: type: PathPrefix value: /api/ method: GET backendRefs: - name: task-api-read-replica port: 8000 # Write operations to primary - matches: - path: type: PathPrefix value: /api/ method: POST backendRefs: - name: task-api-primary port: 8000 - matches: - path: type: PathPrefix value: /api/ method: PUT backendRefs: - name: task-api-primary port: 8000 - matches: - path: type: PathPrefix value: /api/ method: DELETE backendRefs: - name: task-api-primary port: 8000

Test the routes:

bash
# Read replica curl http://localhost:8080/api/tasks # Primary (write) curl -X POST -d '{"title":"New task"}' http://localhost:8080/api/tasks curl -X PUT -d '{"title":"Updated"}' http://localhost:8080/api/tasks/1 curl -X DELETE http://localhost:8080/api/tasks/1

Output:

json
{"source": "read-replica", "tasks": [...]} {"source": "primary", "created": {...}} {"source": "primary", "updated": {...}} {"source": "primary", "deleted": true}

Traffic Weights for Canary Deployments

Traffic weights enable gradual rollouts. Send most traffic to the stable version, a small percentage to the canary.

Basic Traffic Split

yaml
apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: task-api-canary namespace: task-api spec: parentRefs: - name: task-api-gateway rules: - matches: - path: type: PathPrefix value: /api/ backendRefs: - name: task-api-stable port: 8000 weight: 90 - name: task-api-canary port: 8000 weight: 10

Traffic distribution:

  • 90% → task-api-stable
  • 10% → task-api-canary

Test with multiple requests:

bash
for i in {1..20}; do curl -s http://localhost:8080/api/version | jq -r '.version' done

Output:

text
stable stable stable stable canary stable stable stable stable stable canary stable ...

Approximately 2 out of 20 requests go to canary.

Progressive Rollout

Gradually increase canary traffic as confidence grows:

StageCanary PercentageStable WeightCanary Weight
Stage 15%955
Stage 225%7525
Stage 350%5050
Stage 4100%0100

Blue-Green Deployment

For instant cutover, change weights from 100/0 to 0/100:

StateBlue WeightGreen Weight
Before Cutover1000
After Cutover0100

Request Mirroring

Mirror traffic to a shadow service for testing without affecting production responses. The shadow service receives copies of requests, but its responses are discarded.

yaml
apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: task-api-mirror namespace: task-api spec: parentRefs: - name: task-api-gateway rules: - matches: - path: type: PathPrefix value: /api/ backendRefs: - name: task-api port: 8000 filters: - type: RequestMirror requestMirror: backendRef: name: task-api-shadow port: 8000

How it works:

Rendering diagram...

Use cases:

  • Testing new AI model versions with production traffic
  • Validating performance of refactored services
  • Collecting training data from production requests

Verify mirroring:

bash
# Check shadow service logs kubectl logs -l app=task-api-shadow -n task-api --tail=10

Output:

text
2025-12-30T10:00:00Z Received mirrored request: GET /api/tasks 2025-12-30T10:00:01Z Received mirrored request: POST /api/tasks 2025-12-30T10:00:02Z Received mirrored request: GET /api/tasks/123

Multiple Rules and Ordering

Rules are evaluated in order. More specific rules should come first.

Rule Precedence

yaml
apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: task-api-ordered namespace: task-api spec: parentRefs: - name: task-api-gateway rules: # Most specific: urgent tasks endpoint - matches: - path: type: Exact value: /api/v1/tasks/urgent backendRefs: - name: task-api-urgent port: 8000 # Specific: single task by ID pattern - matches: - path: type: RegularExpression value: "/api/v1/tasks/[0-9]+" backendRefs: - name: task-api-read port: 8000 # General: all tasks endpoints - matches: - path: type: PathPrefix value: /api/v1/tasks backendRefs: - name: task-api port: 8000 # Catch-all: everything else - matches: - path: type: PathPrefix value: / backendRefs: - name: default-backend port: 8000

Request routing Summary:

RequestMatches RuleBackend
/api/v1/tasks/urgentRule 1 (Exact)task-api-urgent
/api/v1/tasks/123Rule 2 (Regex)task-api-read
/api/v1/tasksRule 3 (PathPrefix)task-api
/api/v1/tasks/newRule 3 (PathPrefix)task-api
/healthRule 4 (Catch-all)default-backend

Common Ordering Mistakes

Wrong order (specific rule never matches):

yaml
rules: # This catches everything starting with /api/ - matches: - path: type: PathPrefix value: /api/ backendRefs: - name: task-api port: 8000 # This NEVER matches (caught by rule above) - matches: - path: type: Exact value: /api/health backendRefs: - name: health-checker port: 8000

Correct order:

yaml
rules: # Specific rule first - matches: - path: type: Exact value: /api/health backendRefs: - name: health-checker port: 8000 # General rule second - matches: - path: type: PathPrefix value: /api/ backendRefs: - name: task-api port: 8000

GRPCRoute for gRPC Services

For gRPC services, use GRPCRoute instead of HTTPRoute. GRPCRoute understands gRPC semantics like service and method matching.

When to Use GRPCRoute

ProtocolRoute Type
HTTP/1.1, HTTP/2 RESTHTTPRoute
gRPC (HTTP/2 with protobuf)GRPCRoute
gRPC-WebHTTPRoute or GRPCRoute

GRPCRoute Example

yaml
apiVersion: gateway.networking.k8s.io/v1 kind: GRPCRoute metadata: name: task-grpc-route namespace: task-api spec: parentRefs: - name: task-api-gateway rules: # Route by gRPC service name - matches: - method: service: task.TaskService backendRefs: - name: task-grpc-service port: 50051 # Route by specific method - matches: - method: service: task.TaskService method: CreateTask backendRefs: - name: task-grpc-write port: 50051 # Route by method prefix - matches: - method: service: task.TaskService method: Get* type: RegularExpression backendRefs: - name: task-grpc-read port: 50051

Verify GRPCRoute:

bash
kubectl get grpcroute task-grpc-route -n task-api

Output:

text
NAME HOSTNAMES AGE task-grpc-route [] 1m

Gateway Listener for gRPC

Your Gateway needs a listener that accepts HTTP/2 for gRPC:

yaml
apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: task-api-gateway namespace: task-api spec: gatewayClassName: eg listeners: - name: http protocol: HTTP port: 80 - name: grpc protocol: HTTP port: 50051

[!NOTE] gRPC uses HTTP/2, but the protocol field is HTTP. The actual HTTP version negotiation happens at the transport layer.


Exercises

Exercise 1: Create HTTPRoute with PathPrefix

Create an HTTPRoute that routes all /api/ requests to the Task API:

bash
kubectl apply -f - <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: exercise-pathprefix namespace: default spec: parentRefs: - name: task-api-gateway rules: - matches: - path: type: PathPrefix value: /api/ backendRefs: - name: task-api port: 8000 EOF

Verify:

bash
kubectl get httproute exercise-pathprefix

Expected Output:

text
NAME HOSTNAMES AGE exercise-pathprefix [] 1m

Exercise 2: Add Header-Based Routing

Extend your HTTPRoute to route x-version: 2 requests to task-api-v2:

bash
kubectl apply -f - <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: exercise-header namespace: default spec: parentRefs: - name: task-api-gateway rules: - matches: - path: type: PathPrefix value: /api/ headers: - name: x-version value: "2" backendRefs: - name: task-api-v2 port: 8000 - matches: - path: type: PathPrefix value: /api/ backendRefs: - name: task-api-v1 port: 8000 EOF

Test (if services exist):

bash
curl -H "x-version: 2" http://localhost:8080/api/tasks curl http://localhost:8080/api/tasks

Exercise 3: Configure 90/10 Traffic Split

Create a canary deployment with 90% stable, 10% canary:

bash
kubectl apply -f - <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: exercise-canary namespace: default spec: parentRefs: - name: task-api-gateway rules: - matches: - path: type: PathPrefix value: /api/ backendRefs: - name: task-api-stable port: 8000 weight: 90 - name: task-api-canary port: 8000 weight: 10 EOF

Verify weights:

bash
kubectl get httproute exercise-canary -o yaml | grep -A5 backend Refs

Expected Output:

text
backendRefs: - name: task-api-stable port: 8000 weight: 90 - name: task-api-canary port: 8000 weight: 10

Exercise 4: Add Query Parameter Matching

Route debug requests to a debug-enabled backend:

bash
kubectl apply -f - <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: exercise-query namespace: default spec: parentRefs: - name: task-api-gateway rules: - matches: - path: type: PathPrefix value: /api/ queryParams: - name: debug value: "true" backendRefs: - name: task-api-debug port: 8000 - matches: - path: type: PathPrefix value: /api/ backendRefs: - name: task-api port: 8000 EOF

Test (if services exist):

bash
curl "http://localhost:8080/api/tasks?debug=true"

Reflect on Your Skill

You built a traffic-engineer skill in Lesson 0. Based on what you learned about HTTPRoute:

Add Routing Templates

Your skill should now generate HTTPRoute for common patterns:

Path-based template:

yaml
# Template: path-based routing apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: {{ service }}-route namespace: {{ namespace }} spec: parentRefs: - name: {{ gateway }} rules: - matches: - path: type: PathPrefix value: {{ path_prefix }} backendRefs: - name: {{ service }} port: {{ port }}

Header-based template:

yaml
# Template: header-based version routing rules: - matches: - path: type: PathPrefix value: /api/ headers: - name: {{ header_name }} value: {{ header_value }} backendRefs: - name: {{ versioned_service }} port: {{ port }}

Traffic splitting template:

yaml
# Template: canary deployment rules: - matches: - path: type: PathPrefix value: / backendRefs: - name: {{ stable_service }} port: {{ port }} weight: {{ stable_weight }} - name: {{ canary_service }} port: {{ port }} weight: {{ canary_weight }}

What Rule Ordering Should Your Skill Follow?

When generating multiple rules, your skill should order them:

  1. Exact matches first (most specific)
  2. RegularExpression matches second
  3. PathPrefix matches third
  4. Catch-all last (least specific)

This ordering prevents more specific rules from being shadowed by general ones.

Consider GRPCRoute

Your skill should ask about protocol:

User saysGenerate
"REST API"HTTPRoute
"gRPC service"GRPCRoute
"Both REST and gRPC"HTTPRoute + GRPCRoute

Try With AI

Generate Multi-Service Routing

Ask your traffic-engineer skill to generate routing:

text
Using my traffic-engineer skill, generate HTTPRoute configuration for myTask API with these requirements: - /tasks goes to task-api service on port 8000 - /users goes to user-api service on port 8001 - /notifications goes to notification-api service on port 8002 All services are in the task-api namespace.

What you're learning: AI generates routing rules from requirements. Review the output—did AI use the correct path matching type? Are the backend ports correct? Did it order rules appropriately?

Evaluate the Generated Route

Check AI's output:

  • Are parentRefs correctly pointing to your Gateway?
  • Did AI use PathPrefix for catch-all patterns and Exact for specific endpoints?
  • Are all services in the specified namespace?

If the route does not match your requirements, tell AI what needs to change:

text
The HTTPRoute looks good, but I need /tasks/urgent to route to a different service: urgent-task-api on port 8003. Add this as a higher priority rule.

Add Canary Traffic Splitting

Extend the configuration:

text
Add a canary deployment pattern to the /tasks route: - 95% traffic to task-api-stable - 5% traffic to task-api-canary Both services run on port 8000.

What you're learning: AI adapts existing configurations. Review the weights—do they sum correctly? Is the canary service defined with the right port?

Review and Apply

Compare AI's final output to what you learned in this lesson:

  • Do more specific rules come before general rules?
  • Are header matchers using the correct syntax?
  • Would kubectl apply --dry-run=client accept this YAML?

This iteration—specifying requirements, evaluating output, refining with constraints—is how production configurations emerge.

Safety Note

When deploying HTTPRoute changes in production, test with kubectl apply --dry-run=client first. Incorrect routing rules can send traffic to wrong services or drop requests entirely. For canary deployments, start with small weights (1-5%) and monitor error rates before increasing.

Core Concept

HTTPRoute defines sophisticated routing logic with path matching (Exact, PathPrefix, RegularExpression), header matching, query parameter matching, and traffic weights for canary deployments, making it the application developer's primary resource.

Key Mental Models

  • Match Specificity: Exact > RegularExpression > PathPrefix; order rules from most to least specific
  • Header-Based Versioning: Route x-version: 2 to v2 backend without changing URLs
  • Traffic Weights: Relative weights (90/10) split traffic for canary deployments
  • Request Mirroring: Copy traffic to shadow backend for testing; responses discarded

Critical Patterns

  • Use PathPrefix for API namespace routing (/api/v1/)
  • Use Exact for specific endpoints (/health)
  • Use header matching for API versioning without URL changes
  • Use weights for gradual rollouts: 95/5 -> 75/25 -> 50/50 -> 100/0

AI Collaboration Keys

  • Generate multi-service HTTPRoute with different path prefixes
  • Design header-based routing for beta users
  • Configure canary deployment with progressive weight adjustments

Common Mistakes

  • Placing PathPrefix rule before Exact rule (general catches all, specific never matches)
  • Forgetting weights must be relative (9/1 = 90/10 split)
  • Using request mirroring for non-idempotent operations

Connections

  • Builds on: MODULE 7, SUB-MODULE 8, CHAPTER 4 (Envoy Gateway Setup) with running controller
  • Leads to: MODULE 7, SUB-MODULE 8, CHAPTER 7 (Rate Limiting & Circuit Breaking) for traffic policy controls

📋Quick Reference

Unlock Lesson Summary

Access condensed key takeaways and quick reference notes for efficient review.

  • Key concepts at a glance
  • Perfect for revision
  • Save study time

Free forever. No credit card required.