Azure API Management: Building a Scalable API Gateway

Azure API Management: Building a Scalable API Gateway

Introduction

[Explain API gateway pattern benefits: centralized security, throttling, analytics, abstraction; APIM as comprehensive solution.]

Prerequisites

  • Azure subscription
  • Backend APIs (REST, SOAP, GraphQL)
  • Basic API concepts

APIM Architecture

flowchart LR CLIENT[API Consumers] --> APIM[API Management Gateway] APIM --> POLICY[Policy Engine] POLICY --> BACKEND1[Microservice 1] POLICY --> BACKEND2[Microservice 2] POLICY --> BACKEND3[Legacy SOAP] APIM --> PORTAL[Developer Portal] APIM --> ANALYTICS[Analytics & Monitoring]

Core Components

Component Purpose Key Features
Gateway Request routing & transformation Policies, caching, throttling
Developer Portal API documentation & testing Swagger UI, subscriptions
Management API Automation & configuration ARM templates, REST API
Analytics Usage metrics Application Insights integration

Step-by-Step Guide

Step 1: Create APIM Instance

az apim create \
  --resource-group rg-apim \
  --name contoso-apim \
  --publisher-email admin@contoso.com \
  --publisher-name "Contoso Corp" \
  --sku-name Developer

Step 2: Import Backend API

OpenAPI Import:

az apim api import \
  --resource-group rg-apim \
  --service-name contoso-apim \
  --path /products \
  --specification-format OpenApi \
  --specification-url https://api.contoso.com/swagger.json \
  --api-id products-api

Step 3: Configure Inbound Policy

<policies>
    <inbound>
        <!-- Rate limiting -->
        <rate-limit calls="100" renewal-period="60" />
        
        <!-- Validate JWT -->
        <validate-jwt header-name="Authorization" failed-validation-httpcode="401">
            <openid-config url="https://login.microsoftonline.com/{tenant}/.well-known/openid-configuration" />
            <audiences>
                <audience>api://contoso-api</audience>
            </audiences>
        </validate-jwt>
        
        <!-- Set backend service URL -->
        <set-backend-service base-url="https://backend.contoso.com/api" />
        
        <!-- Add correlation ID -->
        <set-header name="X-Correlation-Id" exists-action="skip">
            <value>@(Guid.NewGuid().ToString())</value>
        </set-header>
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <!-- Remove internal headers -->
        <set-header name="X-Internal-Server" exists-action="delete" />
        <base />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>

Step 4: Response Caching

<policies>
    <inbound>
        <cache-lookup vary-by-developer="false" vary-by-developer-groups="false">
            <vary-by-query-parameter>category</vary-by-query-parameter>
        </cache-lookup>
    </inbound>
    <outbound>
        <cache-store duration="3600" />
    </outbound>
</policies>

Step 5: API Versioning

URL Path Versioning:

az apim api create \
  --resource-group rg-apim \
  --service-name contoso-apim \
  --api-id products-v2 \
  --path /v2/products \
  --display-name "Products API v2"

Header Versioning:

<choose>
    <when condition="@(context.Request.Headers.GetValueOrDefault("api-version","") == "2.0")">
        <set-backend-service base-url="https://backend-v2.contoso.com" />
    </when>
    <otherwise>
        <set-backend-service base-url="https://backend-v1.contoso.com" />
    </otherwise>
</choose>

Step 6: Subscription Keys

az apim subscription create \
  --resource-group rg-apim \
  --service-name contoso-apim \
  --name premium-subscription \
  --scope /apis \
  --display-name "Premium Tier"

Policy to Check Subscription:

<inbound>
    <check-header name="Ocp-Apim-Subscription-Key" failed-check-httpcode="401" failed-check-error-message="Missing subscription key" />
</inbound>

Step 7: Developer Portal Customization

[Configure branding, add custom pages, publish API documentation with code samples]

Step 8: Monitoring & Analytics

Application Insights Integration:

az apim logger create \
  --resource-group rg-apim \
  --service-name contoso-apim \
  --logger-id appinsights-logger \
  --logger-type applicationInsights \
  --instrumentation-key {app-insights-key}

Custom Logging Policy:

<log-to-eventhub logger-id="eventhub-logger">
@{
    return new JObject(
        new JProperty("method", context.Request.Method),
        new JProperty("url", context.Request.Url.ToString()),
        new JProperty("responseCode", context.Response.StatusCode)
    ).ToString();
}
</log-to-eventhub>

Advanced Policies

Request Transformation

<set-body>
@{
    var body = context.Request.Body.As<JObject>(preserveContent: true);
    body["timestamp"] = DateTime.UtcNow.ToString("o");
    return body.ToString();
}
</set-body>

Circuit Breaker Pattern

<retry condition="@(context.Response.StatusCode >= 500)" count="3" interval="2" first-fast-retry="true">
    <forward-request timeout="10" />
</retry>

IP Filtering

<ip-filter action="allow">
    <address>192.168.1.0/24</address>
    <address>10.0.0.1</address>
</ip-filter>

Security Best Practices

  • Use managed identities for backend authentication
  • Enable OAuth 2.0 / OpenID Connect
  • Implement IP whitelisting for sensitive APIs
  • Rotate subscription keys regularly
  • Use WAF policies via Azure Front Door

Performance Optimization

  • Enable response caching for read-heavy APIs
  • Use compression (<set-header name="Accept-Encoding" exists-action="override"><value>gzip</value></set-header>)
  • Scale APIM tier based on throughput requirements
  • Place APIM in same region as backend services

Cost Management

Tier Use Case Cost Factor
Consumption Serverless, low volume Per-call pricing
Developer Testing, non-production Fixed monthly
Basic/Standard Production, moderate scale Fixed + capacity units
Premium Multi-region, VNet injection High fixed + capacity

Troubleshooting

Issue: 401 Unauthorized despite valid token
Solution: Check JWT validation policy audience/issuer settings

Issue: High latency
Solution: Review policy execution time in trace logs; optimize backend calls

Issue: Policy expression error
Solution: Use test console to debug; check C# syntax in expressions

Best Practices Summary

  • Version APIs from day one
  • Use policies for cross-cutting concerns (auth, throttling, logging)
  • Enable analytics for usage insights
  • Document APIs thoroughly in developer portal
  • Automate deployment via ARM/Bicep templates

Key Takeaways

  • APIM centralizes API governance and security.
  • Policies enable transformation, caching, rate limiting without code changes.
  • Developer portal accelerates API adoption.
  • Multi-region deployment ensures global availability.

Next Steps

  • Implement OAuth 2.0 authorization flows
  • Set up custom domains with SSL certificates
  • Integrate with Azure Monitor for alerting

Additional Resources


Which API will you secure and scale first?