Section 09

Key concepts for API Management (APIM)

APIM is the "front door and control tower" for your APIs: it secures, shapes, publishes, meters and monitors them. The examples use Azure API Management, but the concepts carry over to Apigee, Kong, MuleSoft and AWS API Gateway.

9.1 What is API Management?

A platform for publishing, securing, transforming, governing and analysing APIs at scale, made of three parts.

Consumersapps, partners, mobile
→
API Gateway (data plane)auth · rate limit · transform · route · cache
→
Backendsmicroservices, Functions, SOAP, SaaS

🚪 Gateway

Runtime proxy. Every call passes through it and policies are applied here.

🛠 Management plane

Where you define APIs, products, policies and users. Exposed through portal, ARM/Bicep, CLI and REST.

🧑‍💻 Developer portal

Self-service site: discover APIs, read docs, try them, sign up, get keys.

  • Why APIM? It moves cross-cutting concerns (security, throttling, logging, transformation) out of every backend into one consistent layer.
  • Vendors: Azure APIM, Google Apigee, Kong, MuleSoft Anypoint, AWS API Gateway, IBM API Connect, WSO2, Tyk.
How to implement it
APIM partLibrary / APIUse it for
Management planeAzure.ResourceManager.ApiManagement + Azure.IdentityScript APIs, products, subscriptions and policies from C# (most teams use Bicep / APIOps instead)
The contract APIM importsMicrosoft.AspNetCore.OpenApiYour ASP.NET Core API emits the OpenAPI document that APIM imports
Gateway (self-built)Yarp.ReverseProxyMicrosoft's .NET reverse proxy, when you need a code-first gateway instead of a managed product
ConsumersMicrosoft.Kiota.Bundle / RefitTyped clients generated from the published spec

APIM in one sentence: the airport for your APIs ✈️

🛂 Security check = auth (JWT, keys, mTLS) 🎫 Boarding pass = subscription / product 🚦 Air traffic control = rate limits and quotas 🗺 Departure board = developer portal 📊 Control tower = analytics

Backends just fly. The airport handles the rest.

#APIM #APIs #Azure #Integration

9.2 Core building blocks

The objects you create and manage in an APIM instance, and what each one is for.

ConceptWhat it isRemember
APIA set of operations (from OpenAPI, WSDL, GraphQL, gRPC or Function import) with a base URL suffixFront-end contract can differ from the backend
OperationOne endpoint + verb, e.g. GET /accounts/{id}Policies can be applied per operation
ProductA bundle of one or more APIs offered to consumers, with terms and limitsOpen vs protected (subscription required). Approval workflow
Subscription / keyGives a consumer access to a product or API. Primary and secondary keysIdentifies the caller and enables metering. It is not strong auth on its own
BackendA reusable definition of the target service (URL, credentials, circuit breaker, load-balanced pool)Use with set-backend-service
PolicyXML rules run on requests and responsesThe real power of APIM
Named valueA reusable config value or secret (can reference Key Vault)Never hard-code secrets in policies
Version / RevisionBreaking vs non-breaking change managementSee 9.5
Users & groupsDeveloper portal identities and visibilityGroups control which products are visible
WorkspacesFederated API management: teams own their APIs inside a shared instanceDecentralised ownership with central governance
Self-hosted gatewayContainerised gateway that runs on-prem or in other clouds, managed from AzureHybrid and low-latency to on-prem backends
TiersConsumption, Developer, Basic, Standard, Premium, plus v2 tiersPremium = multi-region, VNet injection, availability zones
Subscription key (primary / secondary) Product “Partner-Gold” limit 1000/min Accounts API v1 Payments API v2 GET /accounts GET /accounts/{id} POST /payments Developer portal Developer Group sees Products
How to implement it
Building block.NET side
APIs + operationsGenerated from your endpoints by Microsoft.AspNetCore.OpenApi; set WithName / WithSummary so operations get clean IDs and docs
Products, subscriptions, backends, named valuesAzure.ResourceManager.ApiManagement (e.g. ApiManagementServiceResource, ApiManagementProductResource), or APIOps / Bicep
Subscription key (caller)Send Ocp-Apim-Subscription-Key on a typed HttpClient, with the key loaded from Key Vault
Named values from Key VaultAzure.Security.KeyVault.Secrets to rotate the secret; APIM reads it by reference
// Calling an API published through APIM
builder.Services.AddHttpClient<PaymentsClient>(c =>
{
    c.BaseAddress = new Uri("https://contoso-apim.azure-api.net/payments/v1/");
    c.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", builder.Configuration["Apim:Key"]);
})
.AddStandardResilienceHandler();   // retries, timeouts, circuit breaker

9.3 Policies & the request pipeline

Policies are small rules that run in four stages of every call. They're inherited from the global scope down to individual operations.

Client
→
INBOUNDauth · rate limit · validate · rewrite
→
BACKENDroute · retry · forward
→
OUTBOUNDtransform · mask · cache-store
→
Client
ON-ERRORruns if any stage fails: custom error body, logging
Scope inheritance with <base />
Global (all APIs)
→
Workspace
→
Product
→
API
→
Operation

🔐 Access

validate-jwt, validate-azure-ad-token, check-header, ip-filter, authentication-managed-identity, authentication-certificate

🚦 Traffic

rate-limit, rate-limit-by-key, quota, quota-by-key, limit-concurrency

🔄 Transform

set-header, set-body, rewrite-uri, json-to-xml, xml-to-json, find-and-replace

🧭 Routing

set-backend-service, forward-request, retry, send-request, choose (if/else)

⚡ Performance

cache-lookup, cache-store, cache-lookup-value, mock-response

✅ Validation

validate-content, validate-parameters, validate-headers, validate-status-code, cors

Example policy

<policies>
  <inbound>
    <base />
    <!-- 1. Validate the OAuth token from Entra ID -->
    <validate-jwt header-name="Authorization" failed-validation-httpcode="401">
      <openid-config url="https://login.microsoftonline.com/{tenant}/v2.0/.well-known/openid-configuration" />
      <audiences><audience>api://payments</audience></audiences>
    </validate-jwt>
    <!-- 2. 100 calls per 60s per subscription -->
    <rate-limit-by-key calls="100" renewal-period="60" counter-key="@(context.Subscription.Id)" />
    <!-- 3. Call the backend with a managed identity (no secrets) -->
    <authentication-managed-identity resource="api://payments-backend" />
    <set-header name="x-correlation-id" exists-action="skip">
      <value>@(context.RequestId.ToString())</value>
    </set-header>
  </inbound>
  <backend><base /></backend>
  <outbound><base /><set-header name="X-Powered-By" exists-action="delete" /></outbound>
  <on-error><base /></on-error>
</policies>
  • Policy expressions use C# syntax: @(context.Request.Headers...).
  • Keep policies thin. Business logic belongs in services, not the gateway.
  • Use policy fragments to reuse common snippets (e.g. standard JWT validation).
How to implement it
Topic.NET side
Policy expressionsWritten in C# inside @(…) / @{…}, with a limited set of allowed .NET types (e.g. context.Request.Headers.GetValueOrDefault(…), JObject)
Same pipeline in your servicebuilt-in ASP.NET Core middleware and endpoint filters (inbound / outbound / error handling)
Same pipeline in a .NET gatewayYarp.ReverseProxy transforms (AddRequestHeader, AddPathRemovePrefix…) plus auth, rate limiting and output caching middleware
Policies as codePolicy XML stored in Git and published by APIOps (see 9.6)

Keep C# in policies to one-liners. If the expression grows, the logic belongs in a backend service.

9.4 Security in APIM

Secure both legs: consumer → gateway (front door) and gateway → backend (back door).

Client
→WAF / DDoS
Front Door / App Gateway
→JWT · key · mTLS · IP
APIMVNet / private endpoint
→managed identity · cert · private network
Backendonly accepts APIM traffic

Front door (consumer → APIM)

  • OAuth2 / OIDC token validation (validate-jwt)
  • Subscription keys for identification and metering
  • Client certificates (mTLS)
  • IP allow and deny lists, CORS
  • WAF in front (OWASP rules)

Back door (APIM → backend)

  • Managed identity tokens to the backend
  • Client certificate to the backend
  • Private networking (VNet integration, private endpoints)
  • Backend firewall: allow APIM only
  • Secrets in Key Vault through named values
How to implement it
LegLibrary / APIUse it for
Front door (clients)Microsoft.Identity.Client (MSAL) / Azure.IdentityCallers get an Entra ID token that validate-jwt checks
Back door: managed identityMicrosoft.Identity.Web in the backendAccept only tokens for your backend's audience that carry an app role given to APIM's managed identity
Back door: client certificateMicrosoft.AspNetCore.Authentication.CertificateBackend checks the certificate APIM presents
Behind a proxybuilt-in UseForwardedHeaders (KnownProxies / KnownNetworks)Get the real client IP and scheme from X-Forwarded-* headers
SecretsAzure.Security.KeyVault.Secrets, Azure.Extensions.AspNetCore.Configuration.SecretsNo secrets in config files; APIM named values point at the same vault
// Backend: trust only APIM. The token must be for this API and carry the "Gateway.Call" app role,
// which is assigned only to APIM's managed identity (authentication-managed-identity policy)
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));
builder.Services.AddAuthorizationBuilder()
    .SetFallbackPolicy(new AuthorizationPolicyBuilder().RequireRole("Gateway.Call").Build());

If APIM swaps the user's token for its managed identity token, the backend no longer knows the user. When the backend must check object-level access (BOLA), forward the user's token as well and validate it there.

9.5 Versions vs revisions

Version = a breaking change that consumers choose to adopt. Revision = a safe, non-breaking change you test and then make current.

📦 Versions

  • /payments/v1 and /payments/v2 live side by side
  • Scheme: path, header or query string
  • Grouped in a "version set"
  • Consumers migrate at their own pace

📝 Revisions

  • ;rev=3 lets you test before it goes live
  • "Make current" switches traffic over
  • Instant rollback to the previous revision
  • Add a change log entry for consumers
How to implement it
ConceptLibrary / APINotes
Versions in the serviceAsp.Versioning.Http (minimal APIs) / Asp.Versioning.MvcPath, header or query versions, matching the APIM version set scheme
One spec per versionAddOpenApi("v1"), AddOpenApi("v2") (Microsoft.AspNetCore.OpenApi) + Asp.Versioning.Mvc.ApiExplorerImport each document into its own APIM version
Deprecation signalsReportApiVersions = true, sunset policies (Asp.Versioning)Adds api-supported-versions / api-deprecated-versions and Sunset headers
RevisionsNo app code: APIOps or Azure.ResourceManager.ApiManagementA revision is an APIM-side change; your service version stays the same

9.6 API lifecycle & APIOps

Treat APIs as products with a lifecycle, and treat APIM configuration as code.

DesignOpenAPI, contract-first
→
Mockmock-response
→
Build & test
→
Secure & publishproduct
→
Monitoranalytics
→
Version / deprecate
→
Retire
APIOps (GitOps for APIM)
Dev APIMauthor / extract
→
Git repoOpenAPI + policies + config
→
PR review + lintSpectral rules
→
Pipeline publishesTest → Prod APIM
  • Use API design guidelines and linting (naming, versioning, error format) to keep APIs consistent across teams.
  • Keep an API inventory. Unknown "shadow" or "zombie" APIs are a security risk (OWASP API9).
  • Use Bicep or Terraform for the APIM instance, and APIOps tooling for APIs and policies.
How to implement it
StageLibrary / toolNotes
Design / buildMicrosoft.AspNetCore.OpenApi + Microsoft.Extensions.ApiDescription.ServerWrites the OpenAPI file at build time, so the pipeline can lint it and commit it
TestMicrosoft.AspNetCore.Mvc.Testing (WebApplicationFactory)In-memory integration and contract tests against the real pipeline
Publish (APIOps)Azure APIOps toolkit (Azure/apiops on GitHub: extractor + publisher)Not a NuGet package: binaries and pipeline templates that move APIM config through Git
Custom automationAzure.ResourceManager.ApiManagementInventory reports, finding unused ("zombie") APIs, bulk changes
ConsumeKiota CLI + Microsoft.Kiota.BundleRegenerate client SDKs whenever the published spec changes
<!-- .csproj: emit openapi/MyApi.json on every build, ready for lint + APIOps -->
<ItemGroup>
  <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.*" />
  <PackageReference Include="Microsoft.Extensions.ApiDescription.Server" Version="10.*" />
</ItemGroup>
<PropertyGroup>
  <OpenApiDocumentsDirectory>openapi</OpenApiDocumentsDirectory>
</PropertyGroup>

9.7 Monitoring & analytics

Use APIM's monitoring to see who calls which API, how fast it responds, and how often it fails.

  • Don't log full request bodies containing PII or card data. Mask sensitive data in logs.
How to implement it
Library / APIPackageUse it for
Azure Monitor OpenTelemetry distroAzure.Monitor.OpenTelemetry.AspNetCoreSends backend traces, metrics and logs to the same Application Insights as APIM
W3C trace contextbuilt-in System.Diagnostics.ActivityASP.NET Core reads traceparent from APIM and HttpClient passes it on, so one trace spans gateway → services
Custom spans and metricsbuilt-in ActivitySource, MeterBusiness metrics (payments per minute) next to the gateway's request metrics
Mask PII in logsMicrosoft.Extensions.Compliance.RedactionClassify sensitive fields and redact them in logs
builder.Services.AddOpenTelemetry().UseAzureMonitor();   // connection string from config
// APIM -> this API -> downstream calls now appear as one end-to-end transaction

9.8 Gateway patterns & the AI gateway

Standard ways to use a gateway, plus newer policies for fronting LLM APIs.

Gateway routing

One endpoint routes to many services by path or header.

Gateway aggregation

Combine several backend calls into one response.

Gateway offloading

Move TLS, auth, caching and throttling into the gateway.

BFF

A separate API facade per channel (mobile, web, partner).

Façade / modernisation

Modern REST in front of legacy SOAP or mainframe. Part of the strangler fig pattern.

🤖 AI gateway

Front LLM endpoints (Azure OpenAI etc.) with token-based limits (llm-token-limit), token metrics, semantic caching, and load balancing across model deployments.

How to implement it
PatternLibrary / API
Routing / offloadingYarp.ReverseProxy with ASP.NET Core auth, rate limiting and output caching; Ocelot is an older community option
Aggregation / BFFA minimal API per channel calling services with IHttpClientFactory + Task.WhenAll; YARP to forward the rest. Duende.BFF commercial licence for SPA token handling
Façade over legacyREST minimal API calling SOAP through System.ServiceModel.Http (generated with dotnet-svcutil)
AI gateway (client side)Microsoft.Extensions.AI + Microsoft.Extensions.AI.OpenAI / Azure.AI.OpenAI, with the endpoint pointed at APIM instead of the model
// A small .NET gateway: YARP + auth + rate limiting
builder.Services.AddReverseProxy()
    .LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));  // routes + clusters
builder.Services.AddAuthentication().AddJwtBearer();
builder.Services.AddAuthorization();
builder.Services.AddRateLimiter(o => o.AddFixedWindowLimiter("standard", l =>
{
    l.PermitLimit = 100;
    l.Window = TimeSpan.FromMinutes(1);
}));

var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.UseRateLimiter();
app.MapReverseProxy();   // each route sets "AuthorizationPolicy" and "RateLimiterPolicy" in config

Token limits, semantic caching and model load balancing for LLMs (llm-token-limit etc.) are APIM features. In .NET you only change the client's endpoint and credentials.

9.9 API Gateway vs Load Balancer vs Service Mesh vs ESB Added

These four often get mixed up. They sit at different points in the traffic path and solve different problems.

Load balancerAPI gateway / APIMService meshESB / iPaaS
TrafficNorth-south, anyNorth-south (client → APIs)East-west (service ↔ service)System ↔ system
Main jobSpread load, health checksPublish, secure, meter APIsmTLS, retries, observability between servicesOrchestration, transformation, protocol bridging
Knows business?NoLight (policies)NoYes (mappings, flows)
ExamplesAzure LB, App Gateway, NGINXAzure APIM, Apigee, KongIstio, LinkerdMuleSoft, Logic Apps, Boomi, TIBCO
How to implement it
ComponentClosest .NET option
Load balancerInfrastructure, not app code. In-app client-side balancing: YARP clusters or Microsoft.Extensions.ServiceDiscovery
API gatewayYarp.ReverseProxy (self-hosted) or a managed gateway such as Azure APIM
Service meshNo .NET library; the mesh runs as sidecars. Without a mesh: Microsoft.Extensions.Http.Resilience for retries and circuit breakers, OpenTelemetry for tracing
ESB / orchestrationDurable Functions (Microsoft.Azure.Functions.Worker.Extensions.DurableTask), Logic Apps, or messaging with Azure.Messaging.ServiceBus

⚡ Quick-fire Q&A

Is a subscription key enough security?

No. It identifies the calling app and enables metering. Combine it with OAuth2/JWT validation or mTLS for real authentication and authorization.

Product vs API?

An API is the technical interface. A product is the commercial package (one or more APIs + limits + terms) that consumers subscribe to.

How do you roll out a non-breaking policy change safely?

Create a new revision, test it with ;rev=n, make it current, and keep the previous revision for instant rollback.

← 08 · API Design