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?