API Gateway 2026 — Kiến trúc Cổng Trung Tâm cho Microservices với YARP, Kong và BFF Pattern

Posted on: 4/18/2026 10:12:46 AM

Trong kiến trúc microservices, một trong những thách thức lớn nhất là: Client kết nối với bao nhiêu service? Khi hệ thống có 10, 50, hay 200 service, việc để client gọi trực tiếp từng service không chỉ phức tạp mà còn là cơn ác mộng về bảo mật và vận hành. API Gateway chính là lời giải — một cổng trung tâm duy nhất đứng giữa client và toàn bộ backend, xử lý routing, authentication, rate limiting, load balancing và hàng loạt cross-cutting concerns.

Bài viết này sẽ đi sâu vào kiến trúc API Gateway năm 2026, từ các pattern thiết kế cốt lõi, triển khai thực tế với YARP trên .NET 10, so sánh với Kong và AWS API Gateway, đến Backend-for-Frontend (BFF) pattern cho hệ thống production.

1. API Gateway là gì và tại sao Microservices cần nó?

API Gateway là một reverse proxy đứng giữa client (web, mobile, third-party) và các backend services. Thay vì client phải biết địa chỉ và giao thức của từng service, tất cả request đều đi qua một điểm duy nhất — gateway — rồi được route đến đúng service phía sau.

graph TB
    subgraph Clients
        WEB[Web App]
        MOB[Mobile App]
        EXT[3rd-party API]
    end

    GW[API Gateway]

    subgraph Backend Services
        US[User Service]
        OS[Order Service]
        PS[Product Service]
        NS[Notification Service]
    end

    WEB --> GW
    MOB --> GW
    EXT --> GW
    GW --> US
    GW --> OS
    GW --> PS
    GW --> NS

    style GW fill:#e94560,stroke:#fff,color:#fff
    style WEB fill:#f8f9fa,stroke:#e0e0e0,color:#2c3e50
    style MOB fill:#f8f9fa,stroke:#e0e0e0,color:#2c3e50
    style EXT fill:#f8f9fa,stroke:#e0e0e0,color:#2c3e50
    style US fill:#2c3e50,stroke:#fff,color:#fff
    style OS fill:#2c3e50,stroke:#fff,color:#fff
    style PS fill:#2c3e50,stroke:#fff,color:#fff
    style NS fill:#2c3e50,stroke:#fff,color:#fff
Hình 1: API Gateway — điểm trung tâm kết nối client với microservices

Tại sao không gọi trực tiếp từng service?

Khi client gọi trực tiếp: (1) Phải quản lý N endpoint khác nhau, (2) Mỗi service phải tự xử lý auth, rate limiting, CORS, (3) Thay đổi nội bộ (tách/merge service) ảnh hưởng trực tiếp đến client, (4) Không có điểm trung tâm để monitor traffic. API Gateway giải quyết tất cả bằng cách tập trung cross-cutting concerns vào một layer duy nhất.

1.1. Những gì API Gateway xử lý

Routing & Path Rewriting

Map URL public sang internal service endpoints. Ví dụ: /api/orders/* → Orders Service, /api/users/* → User Service. Hỗ trợ path prefix stripping, query string forwarding.

Authentication & Authorization

Validate JWT/OAuth2 token một lần tại gateway, forward claims xuống downstream services. Loại bỏ việc mỗi service phải tự validate token.

Rate Limiting & Throttling

Bảo vệ backend khỏi abuse bằng fixed window, sliding window hoặc token bucket algorithm. Apply theo IP, user, API key hoặc route cụ thể.

Load Balancing

Phân phối traffic qua multiple instances: Round Robin, Least Connections, Weighted, hoặc Consistent Hashing. Kết hợp health checks để loại instance lỗi.

Response Caching

Cache response tại gateway layer cho các endpoint read-heavy, giảm load xuống backend. Hỗ trợ cache invalidation qua header hoặc TTL.

Observability & Logging

Tracing mỗi request từ client đến backend với correlation ID. Export metrics (latency, error rate, throughput) sang Prometheus/OpenTelemetry.

2. Kiến trúc API Gateway — Các Pattern Thiết Kế

2.1. Single Gateway vs Gateway per Client

Có hai cách tiếp cận chính khi thiết kế API Gateway:

graph LR
    subgraph "Pattern 1: Single Gateway"
        C1[All Clients] --> SG[Shared Gateway]
        SG --> S1[Service A]
        SG --> S2[Service B]
    end

    subgraph "Pattern 2: BFF — Gateway per Client"
        WA[Web App] --> WG[Web Gateway]
        MA[Mobile App] --> MG[Mobile Gateway]
        PA[Partner API] --> PG[Partner Gateway]
        WG --> S3[Service A]
        MG --> S3
        PG --> S3
        WG --> S4[Service B]
        MG --> S4
        PG --> S4
    end

    style SG fill:#e94560,stroke:#fff,color:#fff
    style WG fill:#e94560,stroke:#fff,color:#fff
    style MG fill:#e94560,stroke:#fff,color:#fff
    style PG fill:#e94560,stroke:#fff,color:#fff
    style S1 fill:#2c3e50,stroke:#fff,color:#fff
    style S2 fill:#2c3e50,stroke:#fff,color:#fff
    style S3 fill:#2c3e50,stroke:#fff,color:#fff
    style S4 fill:#2c3e50,stroke:#fff,color:#fff
Hình 2: Single Gateway vs Backend-for-Frontend (BFF) Pattern

Single Gateway đơn giản, dễ quản lý, phù hợp hệ thống nhỏ-trung. Nhưng khi Web cần response khác Mobile (ít field hơn, format khác), single gateway trở thành bottleneck — mỗi thay đổi cho mobile ảnh hưởng web và ngược lại.

BFF Pattern (Backend-for-Frontend) giải quyết vấn đề này: mỗi loại client có gateway riêng, tùy chỉnh response shape, aggregation logic và caching strategy theo đúng nhu cầu. Netflix, Spotify và Shopify đều sử dụng BFF cho production.

2.2. Request Pipeline trong API Gateway

Một request đi qua gateway sẽ trải qua nhiều middleware layer theo thứ tự cố định. Thứ tự này cực kỳ quan trọng — đặt sai có thể gây lỗ hổng bảo mật hoặc hành vi không mong muốn.

graph TB
    REQ[Incoming Request] --> CORS[CORS Middleware]
    CORS --> RL[Rate Limiting]
    RL --> AUTH[Authentication]
    AUTH --> AUTHZ[Authorization]
    AUTHZ --> CACHE[Response Cache Check]
    CACHE --> TRANSFORM[Request Transform]
    TRANSFORM --> ROUTE[Route Matching]
    ROUTE --> LB[Load Balancer]
    LB --> HEALTH[Health Check Filter]
    HEALTH --> PROXY[Proxy to Backend]
    PROXY --> RES_TRANSFORM[Response Transform]
    RES_TRANSFORM --> LOG[Logging & Metrics]
    LOG --> RES[Response to Client]

    style REQ fill:#f8f9fa,stroke:#e0e0e0,color:#2c3e50
    style CORS fill:#f8f9fa,stroke:#e94560,color:#2c3e50
    style RL fill:#f8f9fa,stroke:#e94560,color:#2c3e50
    style AUTH fill:#e94560,stroke:#fff,color:#fff
    style AUTHZ fill:#e94560,stroke:#fff,color:#fff
    style CACHE fill:#f8f9fa,stroke:#e94560,color:#2c3e50
    style TRANSFORM fill:#f8f9fa,stroke:#e94560,color:#2c3e50
    style ROUTE fill:#2c3e50,stroke:#fff,color:#fff
    style LB fill:#2c3e50,stroke:#fff,color:#fff
    style HEALTH fill:#2c3e50,stroke:#fff,color:#fff
    style PROXY fill:#2c3e50,stroke:#fff,color:#fff
    style RES_TRANSFORM fill:#f8f9fa,stroke:#e94560,color:#2c3e50
    style LOG fill:#f8f9fa,stroke:#e94560,color:#2c3e50
    style RES fill:#f8f9fa,stroke:#e0e0e0,color:#2c3e50
Hình 3: Request Pipeline — thứ tự middleware trong API Gateway

⚠ Thứ tự middleware quan trọng

Rate Limiting PHẢI trước Authentication. Nếu đặt ngược, attacker có thể spam request với invalid token — gateway vẫn tốn resource để validate JWT trước khi rate limit kick in. Đặt rate limiting trước giúp chặn abuse sớm nhất có thể mà không tốn CPU cho crypto operations.

2.3. Gateway Aggregation Pattern

Một trong những pattern mạnh nhất của API Gateway là request aggregation — gộp nhiều backend calls thành một response duy nhất cho client. Thay vì mobile app gọi 3 API riêng biệt (user profile, orders, recommendations), gateway gọi song song cả 3, merge kết quả và trả về một response.

// Ví dụ aggregation: Client gọi GET /api/dashboard
// Gateway internally gọi song song:
//   GET /users/123/profile
//   GET /orders?userId=123&limit=5
//   GET /recommendations?userId=123
// Merge thành 1 response { profile, recentOrders, recommendations }

Pattern này đặc biệt hữu ích cho mobile app (giảm số lượng HTTP roundtrips trên mạng chậm) và cho trang dashboard (giảm waterfall loading).

3. YARP — API Gateway trên .NET 10

YARP (Yet Another Reverse Proxy) là thư viện mã nguồn mở của Microsoft, được thiết kế như một reverse proxy có thể lập trình hoàn toàn trên ASP.NET Core. Không giống Kong hay AWS API Gateway — là sản phẩm có sẵn feature — YARP là một toolkit để bạn xây dựng gateway theo đúng yêu cầu của mình.

200M+ NuGet Downloads
<1ms Proxy Overhead
100% ASP.NET Core Pipeline
.NET 10 LTS Support

3.1. Cấu hình cơ bản YARP

YARP hoạt động hoàn toàn qua configuration — không cần viết routing logic thủ công. Mỗi route map một URL pattern tới một cluster (nhóm backend instances).

// Program.cs — Minimal API với YARP
var builder = WebApplication.CreateBuilder(args);

// Thêm YARP services
builder.Services.AddReverseProxy()
    .LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));

// Thêm Rate Limiting
builder.Services.AddRateLimiter(options =>
{
    options.AddFixedWindowLimiter("api-limit", opt =>
    {
        opt.PermitLimit = 100;
        opt.Window = TimeSpan.FromMinutes(1);
        opt.QueueLimit = 10;
    });
});

// Thêm Authentication
builder.Services.AddAuthentication("Bearer")
    .AddJwtBearer(options =>
    {
        options.Authority = "https://auth.example.com";
        options.TokenValidationParameters = new()
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidAudience = "my-api"
        };
    });

var app = builder.Build();

app.UseRateLimiter();
app.UseAuthentication();
app.UseAuthorization();
app.MapReverseProxy();

app.Run();
// appsettings.json — YARP routing configuration
{
  "ReverseProxy": {
    "Routes": {
      "orders-route": {
        "ClusterId": "orders-cluster",
        "AuthorizationPolicy": "default",
        "RateLimiterPolicy": "api-limit",
        "Match": {
          "Path": "/api/orders/{**catch-all}"
        },
        "Transforms": [
          { "PathRemovePrefix": "/api/orders" }
        ]
      },
      "users-route": {
        "ClusterId": "users-cluster",
        "Match": {
          "Path": "/api/users/{**catch-all}"
        },
        "Transforms": [
          { "PathRemovePrefix": "/api/users" },
          { "RequestHeader": "X-Forwarded-Prefix", "Set": "/api/users" }
        ]
      }
    },
    "Clusters": {
      "orders-cluster": {
        "LoadBalancingPolicy": "RoundRobin",
        "HealthCheck": {
          "Active": {
            "Enabled": true,
            "Interval": "00:00:30",
            "Timeout": "00:00:10",
            "Path": "/health"
          }
        },
        "Destinations": {
          "orders-1": { "Address": "https://orders-1:5001" },
          "orders-2": { "Address": "https://orders-2:5002" }
        }
      },
      "users-cluster": {
        "Destinations": {
          "users-1": { "Address": "https://users:5003" }
        }
      }
    }
  }
}

3.2. Custom Middleware trên YARP Pipeline

Điểm mạnh lớn nhất của YARP so với các gateway khác: bạn có toàn quyền kiểm soát ASP.NET Core middleware pipeline. Có thể viết middleware tùy chỉnh chèn vào bất kỳ vị trí nào trong pipeline.

// Custom middleware: API Key validation cho partner routes
app.MapReverseProxy(proxyPipeline =>
{
    proxyPipeline.Use(async (context, next) =>
    {
        var route = context.GetReverseProxyFeature().Route;

        if (route.Config.RouteId.StartsWith("partner-"))
        {
            if (!context.Request.Headers
                .TryGetValue("X-API-Key", out var apiKey)
                || !await ValidateApiKey(apiKey!))
            {
                context.Response.StatusCode = 401;
                await context.Response.WriteAsJsonAsync(
                    new { error = "Invalid API key" });
                return;
            }
        }

        await next();
    });

    // Thêm passive health check
    proxyPipeline.UsePassiveHealthChecks();
});

3.3. Health Checks — Active và Passive

YARP hỗ trợ hai loại health check để đảm bảo traffic chỉ đến instances khỏe mạnh:

Active Health Check

Gateway chủ động gọi endpoint /health của mỗi destination theo interval cố định (mặc định 30 giây). Nếu destination không phản hồi hoặc trả status code lỗi, nó bị đánh dấu unhealthy và loại khỏi load balancer rotation. Khi recover, tự động thêm lại.

Passive Health Check

Phát hiện lỗi tại thời điểm request. Nếu destination trả về lỗi (5xx, timeout), YARP đếm failure rate. Khi vượt ngưỡng (ví dụ: 3 lỗi trong 60 giây), destination bị tạm loại khỏi pool. Hoạt động giống circuit breaker — không cần gọi thêm health endpoint.

4. So sánh các API Gateway phổ biến 2026

Tiêu chí YARP (.NET) Kong (OSS) AWS API Gateway Envoy
Kiểu triển khai Library (in-process) Standalone / K8s Managed service Sidecar / Standalone
Ngôn ngữ C# / .NET Lua + Nginx/Kong N/A (managed) C++ / WASM filters
Performance overhead <1ms (in-process) 1-5ms (proxy hop) 5-29ms (managed) ~1ms (sidecar)
Customization Full middleware pipeline Plugin system (Lua/Go) Lambda authorizers WASM / Lua filters
Rate Limiting .NET native (từ .NET 7) Built-in plugin Built-in (throttling) Local/Global filters
Service Discovery Config / Custom provider DNS / Consul / K8s VPC Link / ALB xDS API (Istio)
Health Check Active + Passive Active (upstream) Managed Active + Passive + EDS
Chi phí Miễn phí (OSS) Miễn phí (OSS) / Enterprise $3.50/triệu request Miễn phí (OSS)
Phù hợp với .NET team, full control Multi-language, plugins AWS-native, serverless K8s / Service Mesh

💡 Chọn gateway nào?

Team .NET, muốn full control: YARP — chạy in-process, zero network hop, customize thoải mái bằng C# middleware. Team đa ngôn ngữ, cần plugin ecosystem: Kong — hệ sinh thái plugin phong phú, admin API mạnh. Full AWS, không muốn quản lý infra: AWS API Gateway — managed, auto-scale, tích hợp Lambda. Kubernetes/Service Mesh: Envoy — data plane chuẩn cho Istio, WASM extensibility.

5. Authentication tại Gateway Layer

Một trong những lợi ích lớn nhất của API Gateway là tập trung authentication. Thay vì mỗi service tự validate JWT, gateway validate một lần rồi forward claims (user ID, roles) xuống downstream qua header.

sequenceDiagram
    participant C as Client
    participant GW as API Gateway
    participant IDP as Identity Provider
    participant SVC as Backend Service

    C->>GW: Request + Bearer Token
    GW->>IDP: Validate JWT (cached JWKS)
    IDP-->>GW: Token Valid + Claims
    GW->>GW: Check Authorization Policy
    GW->>SVC: Forward Request + X-User-Id + X-Roles
    SVC-->>GW: Response
    GW-->>C: Response

    Note over GW: Gateway cache JWKS keys
để giảm roundtrip đến IDP
Hình 4: Authentication flow — validate token tại gateway, forward claims xuống service
// YARP: Forward user claims xuống backend service qua header transforms
{
  "Routes": {
    "secured-route": {
      "ClusterId": "backend",
      "AuthorizationPolicy": "authenticated-users",
      "Match": { "Path": "/api/secure/{**catch-all}" },
      "Transforms": [
        { "RequestHeader": "X-User-Id", "Set": "{Claims:sub}" },
        { "RequestHeader": "X-User-Email", "Set": "{Claims:email}" },
        { "RequestHeader": "X-User-Roles", "Set": "{Claims:role}" },
        { "RequestHeaderRemove": "Authorization" }
      ]
    }
  }
}

⚠ Luôn remove Authorization header khi forward

Sau khi gateway validate token, nên strip header Authorization trước khi forward xuống backend. Lý do: (1) Backend không cần validate lại, (2) Tránh token leak nếu backend log request headers, (3) Giảm attack surface — nếu backend bị compromise, attacker không lấy được bearer token từ request.

6. Rate Limiting — Bảo vệ Backend

6.1. Các thuật toán Rate Limiting

Thuật toán Cách hoạt động Ưu điểm Nhược điểm
Fixed Window Đếm request trong window cố định (ví dụ: 100 req/phút) Đơn giản, ít memory Burst ở biên window (199 req trong 2 giây)
Sliding Window Window trượt liên tục, weighted count Smooth hơn fixed window Phức tạp hơn, cần lưu timestamp
Token Bucket Token được thêm đều đặn, mỗi request tiêu 1 token Cho phép burst ngắn, smooth overall Cần tune bucket size + refill rate
Concurrency Limiter Giới hạn số request đồng thời (parallel) Bảo vệ khỏi slow-request attack Không limit throughput tổng thể
// .NET 10: Rate Limiting đa tầng trong YARP
builder.Services.AddRateLimiter(options =>
{
    // Global: 1000 req/phút cho toàn gateway
    options.GlobalLimiter = PartitionedRateLimiter
        .Create<HttpContext, string>(context =>
            RateLimitPartition.GetFixedWindowLimiter(
                partitionKey: "global",
                factory: _ => new FixedWindowRateLimiterOptions
                {
                    PermitLimit = 1000,
                    Window = TimeSpan.FromMinutes(1)
                }));

    // Per-user: 100 req/phút theo user ID
    options.AddPolicy("per-user", context =>
        RateLimitPartition.GetTokenBucketLimiter(
            partitionKey: context.User?.FindFirst("sub")?.Value
                          ?? context.Connection.RemoteIpAddress?.ToString()
                          ?? "anonymous",
            factory: _ => new TokenBucketRateLimiterOptions
            {
                TokenLimit = 100,
                ReplenishmentPeriod = TimeSpan.FromMinutes(1),
                TokensPerPeriod = 100,
                QueueLimit = 10
            }));

    // Strict: cho endpoint nhạy cảm (login, password reset)
    options.AddFixedWindowLimiter("strict", opt =>
    {
        opt.PermitLimit = 5;
        opt.Window = TimeSpan.FromMinutes(15);
    });

    options.OnRejected = async (context, ct) =>
    {
        context.HttpContext.Response.StatusCode = 429;
        context.HttpContext.Response.Headers
            .RetryAfter = "60";
        await context.HttpContext.Response.WriteAsJsonAsync(
            new { error = "Too many requests. Retry after 60 seconds." }, ct);
    };
});

7. Load Balancing và Circuit Breaker

7.1. Chiến lược Load Balancing trong YARP

YARP hỗ trợ nhiều thuật toán load balancing, cấu hình tại cluster level:

Policy Mô tả Use case
RoundRobin Luân phiên qua từng destination Instances đồng nhất về capacity
Random Chọn destination ngẫu nhiên Simple, stateless
LeastRequests Chọn destination có ít active request nhất Instances không đồng nhất, request duration khác nhau
PowerOfTwoChoices Random 2 destinations, chọn cái ít request hơn Balance tốt giữa randomness và load-awareness
FirstAlphabetical Luôn chọn destination đầu tiên theo alphabet Primary-secondary failover

7.2. Circuit Breaker tại Gateway

Khi một backend service bị lỗi liên tục, gateway không nên tiếp tục gửi request đến nó — sẽ gây cascade failure. Circuit Breaker pattern giải quyết vấn đề này:

stateDiagram-v2
    [*] --> Closed
    Closed --> Open : Failure threshold reached
    Open --> HalfOpen : Timeout expires
    HalfOpen --> Closed : Probe request succeeds
    HalfOpen --> Open : Probe request fails

    state Closed {
        [*] --> Monitoring
        Monitoring --> Monitoring : Request OK (reset counter)
        Monitoring --> CountFailure : Request Failed
        CountFailure --> Monitoring : Below threshold
    }
Hình 5: Circuit Breaker state machine — Closed → Open → Half-Open
// Kết hợp YARP với Polly cho Circuit Breaker
builder.Services.AddHttpClient("yarp-forwarder")
    .AddResilienceHandler("gateway-resilience", pipeline =>
    {
        pipeline.AddCircuitBreaker(new()
        {
            SamplingDuration = TimeSpan.FromSeconds(30),
            FailureRatio = 0.5,
            MinimumThroughput = 10,
            BreakDuration = TimeSpan.FromSeconds(15)
        });

        pipeline.AddTimeout(TimeSpan.FromSeconds(10));

        pipeline.AddRetry(new()
        {
            MaxRetryAttempts = 2,
            Delay = TimeSpan.FromMilliseconds(500),
            BackoffType = DelayBackoffType.Exponential,
            ShouldHandle = new PredicateBuilder()
                .Handle<HttpRequestException>()
                .Handle<TimeoutRejectedException>()
        });
    });

8. Backend-for-Frontend (BFF) Pattern — Triển khai thực tế

BFF pattern tạo một gateway riêng cho mỗi loại client, cho phép tùy chỉnh response format, aggregation logic và caching strategy theo đúng nhu cầu từng platform.

graph TB
    subgraph "Client Layer"
        WEB[Vue.js SPA]
        MOB[React Native App]
        IOT[IoT Dashboard]
    end

    subgraph "BFF Layer"
        WBFF[Web BFF
Full response, SSR support] MBFF[Mobile BFF
Compact response, pagination] IBFF[IoT BFF
Minimal payload, batch writes] end subgraph "Domain Services" USER[User Service] ORDER[Order Service] PRODUCT[Product Service] ANALYTICS[Analytics Service] end WEB --> WBFF MOB --> MBFF IOT --> IBFF WBFF --> USER WBFF --> ORDER WBFF --> PRODUCT WBFF --> ANALYTICS MBFF --> USER MBFF --> ORDER MBFF --> PRODUCT IBFF --> ANALYTICS style WBFF fill:#e94560,stroke:#fff,color:#fff style MBFF fill:#e94560,stroke:#fff,color:#fff style IBFF fill:#e94560,stroke:#fff,color:#fff style USER fill:#2c3e50,stroke:#fff,color:#fff style ORDER fill:#2c3e50,stroke:#fff,color:#fff style PRODUCT fill:#2c3e50,stroke:#fff,color:#fff style ANALYTICS fill:#2c3e50,stroke:#fff,color:#fff
Hình 6: BFF Pattern — mỗi client type có gateway riêng với response shape tùy chỉnh
// Web BFF: Aggregation endpoint cho Dashboard page
app.MapGet("/bff/dashboard", async (
    IUserService userService,
    IOrderService orderService,
    IProductService productService,
    HttpContext context) =>
{
    var userId = context.User.FindFirst("sub")!.Value;

    // Gọi song song 3 services
    var profileTask = userService.GetProfileAsync(userId);
    var ordersTask = orderService.GetRecentAsync(userId, limit: 10);
    var recommendationsTask = productService
        .GetRecommendationsAsync(userId, limit: 8);

    await Task.WhenAll(profileTask, ordersTask, recommendationsTask);

    return Results.Ok(new
    {
        Profile = profileTask.Result,
        RecentOrders = ordersTask.Result,
        Recommendations = recommendationsTask.Result,
        ServerTime = DateTime.UtcNow
    });
}).RequireAuthorization();

// Mobile BFF: Compact response, chỉ trả fields cần thiết
app.MapGet("/bff/mobile/dashboard", async (
    IUserService userService,
    IOrderService orderService,
    HttpContext context) =>
{
    var userId = context.User.FindFirst("sub")!.Value;

    var profileTask = userService.GetProfileAsync(userId);
    var ordersTask = orderService.GetRecentAsync(userId, limit: 5);

    await Task.WhenAll(profileTask, ordersTask);

    var profile = profileTask.Result;
    return Results.Ok(new
    {
        DisplayName = profile.DisplayName,
        AvatarUrl = profile.AvatarUrl,
        OrderCount = ordersTask.Result.Count,
        LastOrderStatus = ordersTask.Result.FirstOrDefault()?.Status
    });
}).RequireAuthorization();

9. Observability — Monitoring API Gateway

API Gateway là nơi tốt nhất để đặt observability vì tất cả traffic đều đi qua đây. Cần monitor 4 metrics chính (RED + Saturation):

Rate Request per second (throughput)
Errors Error rate (4xx/5xx %)
Duration Latency percentiles (p50, p95, p99)
Saturation Connection pool, queue depth
// OpenTelemetry integration cho YARP
builder.Services.AddOpenTelemetry()
    .WithMetrics(metrics =>
    {
        metrics.AddAspNetCoreInstrumentation()
               .AddHttpClientInstrumentation()
               .AddMeter("Yarp.ReverseProxy")
               .AddOtlpExporter(opt =>
                   opt.Endpoint = new Uri("http://otel-collector:4317"));
    })
    .WithTracing(tracing =>
    {
        tracing.AddAspNetCoreInstrumentation()
               .AddHttpClientInstrumentation()
               .SetResourceBuilder(ResourceBuilder.CreateDefault()
                   .AddService("api-gateway"))
               .AddOtlpExporter();
    });

// Custom middleware: add correlation ID
app.Use(async (context, next) =>
{
    if (!context.Request.Headers.ContainsKey("X-Correlation-Id"))
    {
        context.Request.Headers["X-Correlation-Id"] =
            Guid.NewGuid().ToString("N");
    }
    context.Response.Headers["X-Correlation-Id"] =
        context.Request.Headers["X-Correlation-Id"];

    await next();
});

10. Best Practices cho Production

💡 10 nguyên tắc thiết kế API Gateway cho Production

  1. Stateless gateway: Không lưu session state tại gateway — dùng JWT hoặc external session store. Cho phép horizontal scale dễ dàng.
  2. Timeout cascade: Gateway timeout phải lớn hơn backend timeout. Ví dụ: backend 5s → gateway 8s → client 15s. Tránh gateway timeout trước khi backend trả response.
  3. Retry chỉ cho idempotent operations: Chỉ retry GET, PUT, DELETE. KHÔNG retry POST (có thể tạo duplicate). Nếu cần retry POST, yêu cầu client gửi Idempotency-Key header.
  4. Rate limit trước auth: Đặt rate limiting ở đầu pipeline để chặn abuse sớm nhất, trước khi tốn CPU cho JWT validation.
  5. Health check riêng cho gateway: Tách /health/live (gateway alive) và /health/ready (gateway + backends ready). Kubernetes dùng liveness và readiness probe khác nhau.
  6. Request/Response size limits: Set max body size (ví dụ: 10MB) để chặn payload abuse. Dùng streaming cho file upload thay vì buffer toàn bộ.
  7. Graceful shutdown: Khi gateway restart, drain active connections trước khi shutdown. YARP hỗ trợ app.Lifetime.ApplicationStopping event.
  8. Configuration hot-reload: Thay đổi routing không cần restart gateway. YARP hỗ trợ IProxyConfigProvider để load config từ DB, Consul hoặc etcd.
  9. Tránh gateway monolith: Không đặt business logic vào gateway. Gateway chỉ xử lý cross-cutting concerns — routing, auth, rate limit, transform. Business logic thuộc về domain services.
  10. Canary routing: Dùng header-based hoặc weight-based routing để rollout version mới dần dần. YARP hỗ trợ HeaderRouteMatch để route theo custom header.

11. Kiến trúc tổng thể — Gateway trong Production Stack

graph TB
    CDN[CDN / Cloudflare] --> LB[External Load Balancer]
    LB --> GW1[API Gateway Instance 1]
    LB --> GW2[API Gateway Instance 2]

    subgraph "Gateway Responsibilities"
        GW1 --> |"Auth, Rate Limit,
Route, Transform"| GW1 end GW1 --> SD[Service Discovery
Consul / K8s DNS] GW2 --> SD SD --> US1[User Service x3] SD --> OS1[Order Service x2] SD --> PS1[Product Service x4] GW1 --> OTEL[OpenTelemetry
Collector] GW2 --> OTEL OTEL --> GRAF[Grafana / Dashboard] style CDN fill:#f8f9fa,stroke:#e0e0e0,color:#2c3e50 style LB fill:#f8f9fa,stroke:#e94560,color:#2c3e50 style GW1 fill:#e94560,stroke:#fff,color:#fff style GW2 fill:#e94560,stroke:#fff,color:#fff style SD fill:#2c3e50,stroke:#fff,color:#fff style US1 fill:#2c3e50,stroke:#fff,color:#fff style OS1 fill:#2c3e50,stroke:#fff,color:#fff style PS1 fill:#2c3e50,stroke:#fff,color:#fff style OTEL fill:#f8f9fa,stroke:#e94560,color:#2c3e50 style GRAF fill:#f8f9fa,stroke:#e94560,color:#2c3e50
Hình 7: Production stack — CDN → Load Balancer → API Gateway → Service Discovery → Backend Services

Kết luận

API Gateway không phải là một component tùy chọn trong microservices — nó là lớp hạ tầng bắt buộc khi hệ thống vượt quá 3-5 services. Bằng cách tập trung routing, authentication, rate limiting và observability vào một điểm duy nhất, gateway giúp team tập trung vào business logic thay vì lặp đi lặp lại cross-cutting concerns ở mỗi service.

Với .NET team, YARP là lựa chọn nổi bật nhờ chạy in-process trên ASP.NET Core pipeline — overhead gần như bằng 0 và tùy chỉnh không giới hạn bằng C# middleware. Với team đa ngôn ngữ hoặc cần plugin ecosystem sẵn có, Kong vẫn là tiêu chuẩn ngành. Còn nếu đã all-in AWS và muốn zero ops, AWS API Gateway là lựa chọn managed đáng cân nhắc.

Dù chọn giải pháp nào, hãy nhớ nguyên tắc vàng: Gateway chỉ xử lý cross-cutting concerns. Business logic thuộc về domain services.

Tài liệu tham khảo