CAMPUX Cloud Bootcamp Phase Two · Class Sixteen
Phase Two — Core Infrastructure
Reading 43 min · Drills 6 · 3 Labs
Aligned to AZ-104
Class Sixteen

REST APIs & ARM

The portal is not Azure — it is one client of Azure, and the moment you see the single API behind every click, the whole platform stops being a set of screens and becomes a system you can read.

§1

The portal is just a client

For fifteen classes you have used the portal as though it were Azure itself. It is not. The portal is a website that, every time you click Create or Save, composes a request and sends it to one place: the Azure Resource Manager, a REST API living at management.azure.com. The CLI you have been running in the labs sends requests to the same API. So do the SDKs, so does Terraform, so does the mobile app. There is exactly one door into your Azure estate, and everything you have used is a client knocking on it.1

ARM
Azure Resource Manager — the single control-plane API through which every resource is created, read, updated and deleted. The portal, the CLI, the SDKs and infrastructure-as-code tools are all just clients of it.

This is the mental shift the whole class exists to cause, and it is the one that separates someone who operates Azure from someone who merely navigates it. Once you know that a click is an HTTP request, three things become possible that were not before: you can make the same change from a script that you made by hand; you can read exactly what the portal did when something goes wrong; and you can reason about permissions and policy as things that happen to requests, not to screens. The rest of this class is those three abilities, and each rests on being able to read one thing — the address of a resource.

§2

The anatomy of a resource ID

Every resource in Azure has a single, canonical address — its resource ID — and it is not a random string. It is a path with a fixed grammar, and reading that grammar fluently is the most transferable skill in this class. Figure 9 takes one apart.

Figure 9: a single Azure resource ID broken into its five segments — subscription, resource group, resource provider, resource type, and resource name — each underlined in red pen and annotated with what it identifies. One resource ID, read segment by segment one address /subscriptions/1a2b…9f /resourceGroups/rg-campux-prod /providers/Microsoft.Storage /storageAccounts /campuxstore the subscription — billing & access the resource group — lifecycle unit the resource provider — service family the resource type the resource’s own name
Figure 9 One address, five segments, always in this order. Read left to right and the ID narrates its own place in the hierarchy from Class Seven — subscription, then resource group, then the provider and type that say what kind of thing it is, then its name. Any Azure resource you will ever touch has an ID of exactly this shape; learn to read it and you can locate, address, and reason about anything in the estate.

Say the segments aloud until they are reflex: /subscriptions/ names the billing-and-access boundary, /resourceGroups/ the lifecycle unit, /providers/Microsoft.Storage the resource provider — the service family that implements this kind of resource — then the type and the name. The resource ID is what --ids takes in the CLI, what a role assignment's scope actually is, and what an ARM request's URL path is built from. It is one string doing the work of an address, a scope, and an API route at once.

§3

API versions, and why scripts rot

Every request to ARM must carry one more thing besides the resource path: an API version. It is a required query parameter — ?api-version=2023-01-01 — and leaving it off is not a warning, it is an error; the request is refused.2

api-version
A dated version stamp, required on every ARM request, that pins which revision of the API — and therefore which fields and behaviours — you are asking for. It is how Azure evolves a service without breaking the callers written against last year's shape.

This is the mechanism, and it is also the answer to a question that puzzles beginners: why does a script that worked last year suddenly behave oddly or fail? Because it pinned an api-version that has since been retired, or because a newer default exposes a field the script did not expect. API versions are a promise of stability — a request for 2021-04-01 keeps meaning what it meant in 2021 — but promises expire. The professional habit is to pin an explicit, recent api-version in anything you automate, and to treat "which version" as a real decision rather than copying whatever a blog post used. Scripts do not rot on their own; they rot because the API moved on and the version stamp did not.

§4

az rest — the escape hatch

The CLI has a friendly command for most things — az storage account create and its kin. But sometimes a service is newer than the friendly command, or exposes something the command does not surface. For those moments there is an escape hatch that reaches ARM directly.

Every click is an API call you can read.

az rest lets you send a raw request to any ARM endpoint while the CLI quietly handles the hard part — acquiring and attaching your access token, so you never touch a credential.3 You give it a method and a URL — the resource path plus an api-version — and it returns the JSON the API returns. It is how you call a preview feature the CLI has not caught up to, script an operation with no dedicated command, or simply see the exact shape of a resource as ARM sees it. Knowing az rest exists is what turns "the CLI can't do that" into "the CLI is just a client, and I can send the request myself." It is the difference between being limited by the tool and being limited only by the API.

§5

The Activity Log is a transcript of the API

Because every change is an ARM request, Azure can — and does — keep a log of them. The Activity Log is that record: every control-plane operation on your resources, with who called it, when, against which resource ID, and whether it succeeded or failed. Read correctly, it is the single best debugging tool in the platform.

What it captures
Control-plane operations — creates, updates, deletes, role assignments, deployments — as API calls: the operation name, the caller, the timestamp, the target resource ID, and the status with any error.
What it does not
Data-plane actions inside a resource — the blobs read, the rows queried. Those live in the resource's own logs, not the Activity Log, because they never went through ARM.

The superpower is this: when the portal throws an error, or a resource ends up in a state nobody admits to causing, you open the Activity Log, find the failed or surprising operation, and read its details — often the raw JSON of the request and the error ARM returned. It tells you the exact call, the exact caller, and the exact reason, where the portal only showed a red banner. "Who deleted the storage account, and when?" is not a mystery; it is a filter on the Activity Log. Learning to reach for it first is what makes an incident a five-minute lookup instead of an afternoon of guessing.

Case File · Campux Retail

Reading the error the portal hid

A red banner · the Activity Log · the real reason

A Campux teammate tries to create a resource in the portal and gets a vague red banner: "The deployment failed." No detail, no cause, just failure. Instead of retrying blindly, you open the Activity Log, filter to the last few minutes, and find the failed operation. Its JSON is unambiguous where the banner was mute: the request was refused by an Azure Policy — the allowed-regions deny from Class Eight — because the teammate picked a region outside the permitted set.

The banner said "it failed"; the Activity Log said why, in the API's own words, naming the policy and the disallowed value. Two minutes, not an afternoon. You show the teammate how to read it themselves, and the lesson of the whole class lands: the portal is a client, the API keeps the receipts, and an engineer who reads the receipts is never stuck at "it failed." That closes Phase Two — you now understand not just the services, but the one system underneath all of them.

Watch · Microsoft Learn

The official reference, and a CAMPUX overview

Read the reference first; watch the overview to see it move
Microsoft Learn · References

What is Azure Resource Manager?
learn.microsoft.com/azure/azure-resource-manager/management/overview

Hands-on: Manage Azure resources by using the REST API
learn.microsoft.com/azure/azure-resource-manager/management/manage-resources-rest

CAMPUX overview video

A short walkthrough of the ARM API behind the portal, reading a resource ID, and the Activity Log will live here. Video to be added.

Lab 1 · Azure CLI

Call the ARM API directly

~10 minutes · Azure Cloud Shell · a throwaway resource group

You will talk to the same API the portal uses — read resources with az rest, address one by its resource ID, and prove for yourself that the api-version is not optional.

  1. Open Cloud Shell — the >_ icon in the top bar — and choose Bash. Grab your subscription id:

    SUB=$(az account show --query id -o tsv)
  2. Call ARM directly to list your resource groups — this is exactly what the portal's list does:

    az rest --method get \
      --url "https://management.azure.com/subscriptions/$SUB/resourcegroups?api-version=2021-04-01"
    What just happened: you sent a raw GET to management.azure.com and got JSON back. az rest attached your access token for you — no credential in sight — which is the whole point of the escape hatch.
  3. Now drop the api-version and watch it be refused:

    az rest --method get \
      --url "https://management.azure.com/subscriptions/$SUB/resourcegroups"
    The lesson: the API returns an error demanding an api-version. It is a required query parameter, not a nicety — the fact from §3, proven at the command line.
  4. Create something, then read it back by its resource ID:

    az group create --name rg-campux-lab --location westeurope
    ID=$(az group show --name rg-campux-lab --query id -o tsv)
    echo "$ID"
    az resource show --ids "$ID"
    On screen: the printed ID has the exact five-segment shape of Figure 9. --ids addresses a resource by that single canonical string — the same string that is a role-assignment scope and an ARM URL path.
  5. Tear down:

    az group delete --name rg-campux-lab --yes --no-wait
Lab 2 · Azure Portal

Catch the portal being a client

~10 minutes · no resource kept · see the API under the screen

This lab does not create anything to keep — it makes the portal show you the API it is about to call and the JSON it stores. Once you have seen it, the screens never look quite the same.

  1. Go to portal.azure.com and open any existing resource (a resource group is fine).

  2. On its Overview, find and click JSON View (top-right).On screen: the resource's full ARM representation — its Resource ID in the five-segment shape, and an API version selector. This is the resource as the API sees it, not as a form renders it.

  3. Begin creating a resource — say a storage account — and fill in the Basics, but stop at Review + create.

  4. Instead of creating, click Download a template for automation (a link on the review step).On screen: the ARM template and parameters the portal was about to submit — the exact request behind the button. Every click really is an API call; here is the one you were about to send.

  5. Discard the create (close it — nothing was deployed).The lesson: you just read the portal's homework. Anything the portal can do, it does by composing this request — which means you can compose it too, from a script or a template.

Portal wording drifts; if a label here does not match your screen, the anchors are the resource's JSON View and the "Download a template for automation" link on Review + create.

Lab 3 · Explore the Activity Log

Read the transcript of the API

~5 minutes · look, do not change — learn the log by its screens

Open the record of everything that has gone through ARM and read a few operations as the API calls they are.

  1. In the top search bar, open Activity log (or open a resource group and select its Activity log blade).On screen: a list of operations — create, update, delete — each with the caller, a timestamp, a target resource, and a status. This is the control plane, written down.

  2. Click any operation, then open its JSON.On screen: the operation name, the resource ID it targeted, the caller identity, and — on a failure — the exact error ARM returned. This is the detail the portal's red banners hide.

  3. Use the filters (time range, resource group, status = Failed) to isolate a specific event.The point: "who did what, when, and why did it fail" is a filter here, not a mystery. Reaching for this first is the debugging superpower of the whole class.

On the job

The portal is just a client

You · Cloud Engineer · the portal is not enough

You need the same tag on three hundred resources, and clicking is not an option. You reach for the REST and ARM layer beneath the portal, script the change, and run it once. The realization sticks: the portal is just a client, and everything it does is an API call you can make yourself — which is the door to automating anything in Azure.

Class Sixteen

Examination

Four drills, then two situations. The situations have no marking scheme — write your answer before you reveal the reasoning, or the exercise is worthless. Nothing is stored; this is between you and the page.

Drill 01Recall · parse the ID
In the resource ID /subscriptions/8f.../resourceGroups/rg-store/providers/Microsoft.Storage/storageAccounts/campuxstore, which segment names the resource provider?
Marked

Microsoft.Storage. The provider is the service family, named after /providers/. C is the resource type within that provider, A is the resource group, and D is the resource's own name. Reading the segments in order — provider, then type, then name — is what lets you tell "what kind of thing" a resource is from its ID alone, without opening it.

Drill 02Recall
You send a request to management.azure.com but omit the api-version query parameter. What happens?
Marked

C. ARM requires an explicit api-version on every request and refuses those without one — there is no silent default. A and B are the comfortable assumptions that make people leave it off; the API does neither. This is also why automation should pin a specific, recent version: the parameter is mandatory, and which value you choose decides which fields and behaviours you get. Scripts rot when that pinned version is retired.

Drill 03Select three
Which three are true of Azure Resource Manager and the Activity Log?
Marked

One API behind every client, the Activity Log as a control-plane transcript, and az rest handling the token. The two false statements mark the boundaries: reading a blob is a data-plane action that never touched ARM, so the Activity Log does not see it — it lives in the storage account's own logs; and a resource ID always begins with its subscription, because that is the top of the addressable hierarchy. Confusing control plane with data plane is the classic mistake when hunting for a log that isn't there.

Drill 04Spot the error
A colleague pasted a resource ID into a script. One thing makes it malformed. Which?
RESOURCE ID under review

/subscription/8f2a-.../resourceGroups/rg-store/
  providers/Microsoft.Storage/storageAccounts/campuxstore
Marked

A. The first segment is /subscriptions/, plural — a singular /subscription/ is not a valid ARM path and any call built from it will fail to resolve. B is wrong: the segment keywords are fixed as ARM defines them (it is resourceGroups), and casing of the keywords is part of the grammar; C is wrong because provider namespaces are dotted by design (Microsoft.Storage); D is nonsense.

Consider the consequence. A single mistyped segment means every command using that ID — a show, a role assignment scope, an az rest URL — targets a path that does not exist, and the error you get back ("resource not found") sends you hunting for a missing resource when the resource is fine and the address is wrong. Reading the ID's grammar segment by segment is how you catch this in a second.

Situation 01Write before you reveal
A teammate clicks a button in the portal and gets a red banner: "Operation failed." No other detail. They message you, ready to just try again. What do you tell them to do, and why?
Writing it down first is the exercise. Reading the answer first is not.
Reasoning

Do not retry a failure you have not read. Retrying blind either reproduces the same error or, worse, half-succeeds and leaves a mess. The banner is the portal being a thin client — it showed you that a request failed but not the API's actual response. The detail exists; it is just not on screen.

Send them to the Activity Log. Open it, filter to the last few minutes and status Failed, find the operation, and open its JSON. That record has what the banner omitted: the operation, the target resource ID, the caller, and the exact error ARM returned — a policy denial, a quota limit, a name collision, a missing permission. The cause is almost always stated plainly there.

Then fix the cause, not the symptom. If it was the allowed-regions policy, pick a permitted region; if a quota, request more or choose a smaller size; if permissions, get the right role at the right scope. The habit you are teaching is the whole class: when Azure says "failed," the API already said why — read the receipt before you touch anything.

Situation 02Write before you reveal
A new team member says: "I only ever use the portal — I don't need to know about this ARM API or resource IDs, that's for people who write scripts." Make the case for why the API model matters even to someone who lives in the portal.
The portal user already depends on ARM constantly. Show them where.
Reasoning

They already use the API — they just cannot see it. Every click they make is an ARM request; the portal is only a form that composes one. So this is not a topic for "script people" — it is the substrate under the buttons they press all day. Understanding it does not add a tool; it explains the tool they already have.

Tie it to things they hit weekly. A permission error is a request ARM refused — knowing that sends them to check role and scope, not to refresh the page. A vague failure is a receipt in the Activity Log. A resource ID is what they paste when support asks "which resource," and reading its segments tells them what they are looking at. Every one of these is a portal experience made legible by the API model.

Frame the career point without preaching it. The engineer who knows the portal is a client can reproduce a fix, read a failure, and eventually automate the boring parts — which is the difference between operating Azure and clicking through it. They do not have to write scripts today; they do have to know that what they are doing is, underneath, exactly what a script would do.

Examination record · first attempt
0/4
Class Sixteen · Complete
Retain this much

Five things worth carrying out of this class

  1. The portal is one client of Azure Resource Manager. The CLI, SDKs and IaC tools are clients of the same single control-plane API.
  2. A resource ID has a fixed grammar: subscription, resource group, provider, type, name. It is an address, a scope, and an API path at once.
  3. Every ARM request needs an api-version. It is required, not defaulted — and pinning an old one is why automation rots.
  4. az rest sends a raw request to ARM and attaches your token — the escape hatch when the friendly command cannot do what you need.
  5. The Activity Log is a transcript of control-plane API calls. When the portal says "failed," the log says why. Read it first.
Notes
  1. "Control plane" is the precise term for this API — the layer that creates and manages resources, reached at management.azure.com. It is distinct from the data plane, the per-service endpoints where you use a resource (blobs at *.blob.core.windows.net, and so on). This class is entirely about the control plane; the distinction returns whenever you go looking for a log or a permission and must first ask which plane it lives on.
  2. Treat specific api-version dates as examples, not gospel — the current versions for any service are on its REST reference page and change over time. The durable facts are that the parameter is mandatory on every request and that pinning an explicit, recent value is the habit that keeps automation working; the exact date you pin is a decision to revisit, not a constant.
  3. Under the hood, az rest obtains a token the same way az account get-access-token would and sends it as a bearer token — which is why you never paste a credential. This is also the cleanest way to see that authentication (proving who you are) and the request are separate steps: the token answers "who," the URL and body answer "what."