API Gateway Concepts & Where APIM Fits

Why this matters

You already know how to give a backend a URL — external ingress on a Container App (track 06), an Ingress controller in front of an AKS Service (track 07). But a URL is plumbing, not a product: it has no way to identify who's calling, throttle abuse, version safely, or show you per-consumer usage. An API gateway is the layer that turns raw endpoints into governed, measurable API products, and Azure API Management (APIM) is Azure's managed version of that layer. This module builds the mental model before you provision anything, so every later command has a place to hang.

Concepts

A raw endpoint is not a managed API

In track 06 you ran az containerapp ingress enable --type external and got an FQDN that returned 200 from the internet. In track 07 you pointed an Ingress controller at a Service and did the same. Both are real, working HTTP endpoints — and that's all they are. There's no notion of "who is allowed to call this," "how often," "which version of the contract they're using," or "how many calls did customer X make last month." The endpoint's job ends at routing bytes to a container. Everything that makes an endpoint a product — identity of the caller, limits, packaging, analytics, a contract you can publish — has to be added on top. That's the gap an API gateway fills.

The gateway pattern, in brief

The generic pattern — a reverse proxy at the edge that owns the concerns every request shares (auth termination, rate limiting, routing, TLS, logging), how it differs from an Ingress controller and a service mesh, and when a gateway earns its complexity — is taught in full in API Gateways and Backend-for-Frontend. The short version for this track: an API gateway is one front door for many backends, the same "traffic enters at one controlled edge" idea as the Ingress controller in track 07 and the Envoy-based ingress fronting Container Apps in track 06, generalized so the edge also authenticates, rate-limits, meters, versions and reshapes — once, instead of in every backend.

Where APIM sits relative to Ingress and a service mesh

The three edge technologies you'll meet on Azure answer different questions. The Ingress controller (track 07) asks "which pod?" — L7 routing into a cluster. A service mesh (track 13) asks "can service A call service B, securely?" — east-west traffic between services. APIM, as the API gateway, asks "is this consumer allowed to use this API product, within their quota, on this version?" — north-south traffic at the product edge, between your organization's APIs and their consumers (partners, mobile apps, other teams). APIM sits in front of an Ingress or Container App, not instead of it.

What APIM adds on top of the endpoint

Concretely, APIM layers five things onto a backend you already have:

  • Policies — a per-API/per-operation pipeline (inbound → backend → outbound → on-error) where you enforce rate limits, quotas, IP filtering, JWT validation, and request/response rewriting. This is the heart of the product (module 03).
  • Subscription keys — a simple issued credential (Ocp-Apim-Subscription-Key header) that identifies which consumer is calling, so you can meter and throttle per consumer (module 04/06).
  • Products — a package that groups one or more APIs with a policy and a subscription model, so "the Partner API bundle, 1000 calls/day" is a first-class thing consumers subscribe to (module 06).
  • Developer portal — an auto-generated, brandable website where consumers read your API docs, get keys, and try calls (module 06).
  • Analytics — built-in per-API/per-consumer usage, latency, and error reporting, integrable with Application Insights (module 07).

The backend doesn't change. APIM wraps it.

Where APIM sits in a request's life

Follow one call. A partner's app sends GET https://<your-apim>.azure-api.net/orders/42 with a subscription key header. APIM terminates TLS, matches the request to an API and operation, runs the inbound policies (validate the key, check the rate limit, validate a JWT, maybe rewrite the path), then forwards to the configured backend — which is your Container App's internal FQDN or your AKS Ingress. The backend responds; APIM runs outbound policies (strip an internal header, cache the response), and returns it to the caller. Along the way it records the call for analytics. The consumer never sees the backend URL, never holds a backend credential, and is subject to your rules — that's the product boundary the rest of this track builds out.

Command reference

This module is conceptual — the only commands are read-only orientation ones you run against resources you already have from tracks 06/07, plus checking that the APIM CLI extension is present. Real provisioning starts in module 01.

Command What it does Example
az extension add --name apim Ensure the APIM CLI extension is installed az extension add --name apim
az apim -h List the APIM command groups (orientation) az apim -h
az containerapp show (ingress) Read a Container App's FQDN — a candidate backend az containerapp show --name web --resource-group rg-aca --query properties.configuration.ingress.fqdn -o tsv
az provider show Confirm the APIM resource provider is registered az provider show --namespace Microsoft.ApiManagement --query registrationState -o tsv

Flag-by-flag breakdowns:

az apim show --name <instance> --resource-group <rg> --query "{gateway:gatewayUrl, portal:developerPortalUrl, sku:sku.name}" -o jsonc

  • --query "{...}" — a JMESPath projection pulling just the three fields that matter for orientation: the gateway URL (where consumers call), the developer portal URL (module 06), and the SKU/tier (the cost lever from the track intro). You'll run this for real once an instance exists in module 01.
  • -o jsonc — colorized JSON so the shape is readable.

az provider show --namespace Microsoft.ApiManagement --query registrationState -o tsv

  • --namespace Microsoft.ApiManagement — the Azure resource provider that must be Registered on your subscription before you can create an APIM instance.
  • -o tsv — bare value, easy to test in a script. If it prints NotRegistered, run az provider register --namespace Microsoft.ApiManagement (module 01 covers this).

Hands-on exercises

No APIM instance is created here — nothing bills. These exercises cement the mental model against resources you can stand up cheaply or already have.

  1. Confirm your tooling and provider. Install the extension and check the provider:

    az extension add --name apim
    az provider show --namespace Microsoft.ApiManagement --query registrationState -o tsv
    

    If it prints anything other than Registered, run az provider register --namespace Microsoft.ApiManagement and re-check in a few minutes. (Registration is a one-time, free, per-subscription step.)

  2. Stand up a cheap backend to think about. Reuse the track-06 pattern — deploy a public Container App you'll conceptually front later:

    az group create --name rg-apim-m00 --location eastus
    az containerapp env create --name env-m00 --resource-group rg-apim-m00 --location eastus
    az containerapp create --name orders --resource-group rg-apim-m00 --environment env-m00 `
      --image mcr.microsoft.com/k8se/quickstart:latest --target-port 80 --ingress external
    $fqdn = az containerapp show --name orders --resource-group rg-apim-m00 --query properties.configuration.ingress.fqdn -o tsv
    curl "https://$fqdn"
    

    You get a 200. Write down everything this endpoint does not give you from the "what APIM adds" list (identity of caller, rate limit, versioning, metering, portal).

  3. Prove the endpoint has no consumer identity. From two different machines or two shells, curl the FQDN. Note that the backend cannot tell the two callers apart — there's no key, no per-consumer anything. This is the concrete thing subscription keys will fix.

  4. List the properties an API product would need. On paper, sketch what "Orders API, Free tier: 100 calls/day" would require: a credential to identify the consumer, a counter, a limit, a rejection response, and a usage report. Map each to the APIM feature that provides it (subscription key, rate-limit policy, quota policy, 429 response, analytics).

  5. Draw the request path. For a hypothetical GET https://<apim>.azure-api.net/orders/42, write the ordered stages: TLS terminate → match API/operation → inbound policies → backend forward → outbound policies → response → analytics. For each stage, name one thing that could go wrong (wrong key, over quota, backend 503, header not stripped).

  6. Contrast the three edge technologies. In a small table, fill in Ingress (track 07) vs. service mesh (track 13) vs. API gateway (this track) across three columns: primary traffic direction (north-south vs east-west), primary question it answers, and does APIM replace it or sit in front of it. Confirm your answers against the "where APIM sits relative to Ingress and a service mesh" concept.

  7. Diagnose (paper) a misplaced responsibility. A teammate says "we don't need APIM, we already have rate limiting in the Ingress controller's nginx config." List two things they still can't do that APIM provides (per-consumer metering/quotas tied to an issued key; a self-service developer portal), and one reason centralizing at the gateway beats per-backend config (one place to enforce, consistent across many backends/teams).

  8. Cleanup.

    az group delete --name rg-apim-m00 --yes --no-wait
    

    (This module created only a Container App and Environment — cheap, but delete them anyway so nothing lingers before module 01.)

Independent challenge

Without provisioning APIM, produce a one-page written "API product proposal" for the orders Container App you deployed in the exercises. It must name: the consumers (e.g. an internal mobile team and an external partner), how each will be identified at the gateway, at least two limits you'd enforce and why, the versioning approach you anticipate needing, and what analytics you'd want to report monthly. Draw explicitly on track 06 (which ingress mode the backend uses today and how that changes once APIM fronts it) and track 07 (how this gateway relates to an Ingress controller you already understand). The goal is to be able to defend why each APIM feature exists before you touch a single az apim command. Tear down any leftover Container App resources when done.

Stuck? One hint

Anchor the proposal on the "what APIM adds" list (policies, subscription keys, products, developer portal, analytics) and, for each item, write one sentence: "the raw Container App FQDN can't do X, so APIM's Y provides it." If you can write that sentence honestly for all five, you've understood where APIM fits — and you've also written the requirements for your own capstone.

Common mistakes & troubleshooting

  • Thinking APIM replaces your Ingress/Container App. It doesn't — it sits in front. The backend keeps its ingress; APIM becomes the public front door and the backend ideally becomes internal-only later (module 05).
  • Confusing a gateway with a mesh. A mesh governs service-to-service (east-west) traffic inside the platform; a gateway governs consumer-to-API (north-south) traffic at the product edge. They coexist; APIM is the latter.
  • Assuming "it has a URL, so it's an API." A URL routes bytes. A managed API adds identity, limits, versioning, packaging, and analytics — none of which a bare FQDN provides.
  • Cost pitfall (get ahead of it now). The moment you create a non-Consumption APIM instance in later modules, it bills continuously. Nothing in this module creates one — but internalize the rule before module 01: classic tiers bill whether or not traffic flows; delete them the same day.
  • Skipping provider registration. If Microsoft.ApiManagement isn't Registered, your first az apim create fails with a provider error, not a helpful message. Register it once, up front.

Checkpoint quiz

Write down your answer to each question before expanding it — checking without attempting first is the single easiest way to fool yourself into thinking you've learned this.

  1. Give three capabilities a managed API product has that a bare Container App external FQDN does not.
  2. In one sentence each, distinguish an Ingress controller, a service mesh, and an API gateway by the primary question each answers.
  3. Does APIM replace your AKS Ingress controller or sit in front of it? Why?
  4. List, in order, the stages a request passes through inside APIM from TLS termination to analytics.
  5. What is a subscription key for, and what problem from exercise 3 does it solve?
  6. Name the five things this module said APIM layers on top of a backend.
  7. Why is centralizing rate limiting at the gateway often better than configuring it per-backend (e.g. in each nginx Ingress)?
Show answers
  1. Any three of: identifies the calling consumer (subscription keys); enforces per-consumer rate limits/quotas; versioning of the contract; a self-service developer portal; per-consumer/per-API analytics; centralized auth (JWT validation) at the edge.
  2. Ingress: "which Service/pod does this host/path route to?" Mesh: "can service A call service B, securely (mTLS/authz), east-west?" Gateway: "is this consumer allowed to use this API product, within quota, on this version, north-south?"
  3. It sits in front of it. APIM is the public product edge; the Ingress controller keeps routing inside the cluster. Ideally the backend becomes internal-only once APIM fronts it.
  4. TLS terminate → match API/operation → inbound policies → forward to backend → outbound policies → return response → record analytics.
  5. It's an issued credential (Ocp-Apim-Subscription-Key) that identifies which consumer is calling, so APIM can meter and throttle per consumer — solving the "the backend can't tell two callers apart" problem.
  6. Policies, subscription keys, products, developer portal, analytics.
  7. One place to enforce a consistent rule across many backends and teams (no per-backend reinvention), plus the gateway can tie the limit to an issued consumer identity (the subscription key), which a backend's generic nginx limit can't.

Next

01-provisioning-apim-and-importing-a-first-api — choose a tier (including the cheap Consumption tier), provision an instance (this is the slow one — 30-45 min for classic tiers), and import an OpenAPI spec that fronts one of your Container Apps / AKS backends.