Azure APIM Emulator
— latest release →A clean-room Go implementation of the Azure API Management contract: the ARM management plane, the gateway, and the policy engine with its C# expression language. It runs on a laptop, starts in under a second, and accepts the same SDKs, the same policy XML and the same Ocp-Apim-Subscription-Key a real instance does.
Switching to real Azure is configuration, not a code path.
Every capability below names the check that proves it. Where the evidence is a document rather than a tenant, this page says so.
API Management policy is code that runs only in Azure. That makes it the part of a platform you can test least and break most expensively.
A rate-limit or validate-jwt policy has no local runtime. The feedback loop is deploy, wait, call, read the trace, repeat, against a billed instance shared with colleagues.
The gateway, the policy engine and the expression language, on your machine
Expressions like @(context.Request.Headers.GetValueOrDefault("x")) are validated by a tenant at save time and by nothing before that. A typo is a 500 in production.
A compiler for the documented subset, derived from Microsoft's own reference
An emulator that agrees with itself is a mirror. The only evidence worth having comes from something you did not write: Microsoft's SDKs, a certified OpenID provider, gRPC and SOAP clients.
Third-party clients drive every protocol in CI, and the ledger says which
Each capability carries its evidence tier and an honest status. The tiers are ranked: a packaged third-party client over a network outranks Microsoft's own SDK in-process, which outranks our own tests.
Services, APIs, operations, products, subscriptions, named values, backends, certificates, loggers, diagnostics and more, over the 2024-05-01 stable contract. Conditional requests, collection queries, the error envelope, and Entra-authenticated calls.
HTTP routing, WebSockets and SSE, GraphQL with synthetic resolvers, gRPC over real HTTP/2, SOAP from WSDL, and an MCP server. Subscription keys, products and operation matching behave as the tenant's do.
XML policies compiled and run in every section, with inheritance across service, product, API and operation scope. Rate limits and quotas count per subscription in the windows Microsoft documents. The attribute surface of each policy is derived from the vendored reference page, not transcribed, so an attribute Azure rejects is rejected here.
A hand-written parser and evaluator for the documented subset: the context object, lambdas, interpolated strings, new, casts, null-conditionals, named arguments, and the .NET members Microsoft allows. The member list is derived from two Microsoft sources at pinned commits; any disagreement between them stays visible.
validate-jwt fetches signing keys and issuer from an OpenID discovery endpoint with the cache Microsoft documents, requires exp by default, and honours clock-skew, require-scheme and the output variable.
Token rate limits per minute and token quotas over fixed periods, token metrics with dimensions, and semantic caching's absence stated plainly. Streamed answers are counted byte-for-byte.
Workspace scoping across every resource family, Azure RBAC with deny-by-default, and self-hosted and workspace gateways that serve only their associated APIs. Networking, private endpoints and custom domains are modelled; tiers and SKUs enforce on opt-in.
Not started, and deprioritised on purpose: the management and gateway surfaces are what a platform team tests against. The ledger carries it as a row so the gap is visible rather than forgotten.
The differential harness is built and has never run: it needs a real APIM instance and a bearer token. Until it does, every green row on this page rests on Microsoft's documents and third-party clients, which is the strongest evidence available and still not Azure.
The numbers above are not typed into this page. The build fails if they are.
Every capability the parity ledger grades green must name a witness in docs/witnesses.json, and CI fails if a named witness stops existing. A renamed test that leaves a green row behind is a lie the reader cannot see, so the manifest is what makes the claim checkable.
ci:a CI job driving a packaged external client over a network. The strongest tier.
sdk:Microsoft's own client does the talking, in-process.
go:our own client on both ends. Proves the emulator agrees with itself.
verifiedcompared against a running Azure instance. —
Three ledgers are derived rather than written. The policy inventory and the expression member list are regenerated from Microsoft's vendored pages at pinned commits, and a hand-edit that disagrees with the derivation fails CI. The policy corpus is a ratchet: an expression that parsed yesterday must parse today.
One binary, or one container. No database to provision.
docker pull ghcr.io/calvinchengx/azure-apim-emulator:latest
Or the Go module, the Homebrew tap, or a release archive: see installation.
With the Entra emulator beside it, the management plane authenticates the way Azure does.
git clone https://github.com/calvinchengx/azure-apim-emulator
cd azure-apim-emulator
make up # entra-emulator pinned, apim built from source
make status # the pair is healthy
Then follow the quickstart: publish an API, attach a policy, call it through the gateway with a subscription key, and read the trace.