Skip to content
CAMPUX Cloud Bootcamp Phase Two · Class Sixteen
Phase Two — Core Infrastructure
4 drills · 2 situations · 3 Labs
Aligned to AZ-104
Class Sixteen

REST APIs & ARM

The portal is a client of Azure's management APIs. Learn to read one ARM request, its resource ID, and its response, then trace a failed change without guessing at the screen.

Phase Two · Core Infrastructure · Class 16 of 42 · 22 min · Assumes Class 7

After this you can read an ARM request, say what a resource provider is, and see the portal as one client of the same API.

New to this? Read Class 7 first. Already done it, or know the material? Carry on.

● Screen walkthrough Not yet recorded · ~7 min
Reel · 00:00 / 07:00

Fire an ARM/REST call from the CLI, read the JSON, and map it back to the portal action.

Placeholder — the class below stands alone until the reel lands
§1

The portal is just a client

Three words carry this class. A request is a message your tool sends to a web address: a verb (GET to read, PUT to create or replace, DELETE to remove), the address, and sometimes a body. A response is what comes back: a status number (200 means it worked, 404 means not found, 403 means not allowed) and usually a body. That body is almost always JSON, text arranged as names and values inside braces, such as {"name": "rg-shop", "location": "westeurope"}. If you want a slower introduction with a story, Class 38 Part A stands on its own.

When you create or change an Azure resource in the portal, the screen is a client of Azure Resource Manager (ARM), the management API at management.azure.com. The Azure CLI, SDKs, and infrastructure tools also use ARM for management operations. Reading a blob or sending a message uses a service's data-plane endpoint instead. One screen can use both kinds of API; this class focuses on the management side.1

ARM
Azure Resource Manager — the management layer used to create, read, update, and delete Azure resources. Portal screens, CLI commands, SDKs, and infrastructure tools can call it. A service's data-plane API handles use of that resource, such as reading a blob.

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.

Fig. 1 · Several management clients can call ARM
Portal az CLI Terraform SDKs Azure Resource Manager management.azure.com one REST API Subscription · 1a2b…9f rg-campux-prod campuxstore Microsoft.Storage one request management calls use ARM
The portal, CLI, Terraform, and SDKs can all call ARM for management work. The storage account here lives inside a resource group and subscription. Other resource scopes have different ID shapes, and using a service's data plane is a separate path.
§2

The anatomy of a resource ID

Azure resources have resource IDs: paths that identify where a resource lives. Figure 2 shows a common resource-group-scoped storage account. Read this example first; subscription-level resources and nested child resources have different path shapes.

Figure 2: 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 2 This storage account ID has five labelled parts. Read from subscription to resource group, provider, type, and name. Other resources can live at subscription, management-group, or tenant scope; a child resource adds more type/name pairs. Use the ID the resource actually reports instead of assembling one from memory.

In this ID, /subscriptions/ identifies the subscription, /resourceGroups/ the group, and /providers/Microsoft.Storage the resource provider that implements the service. The type and name finish the address. You can pass the complete ID to commands accepting --ids, use it as a role-assignment scope, or place it in the route of a resource-specific ARM request. A resource group itself has a shorter ID; a child resource has a longer one.

§3

Choose the API version the operation supports

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.

Each resource provider publishes supported API versions for its operations. A version used in one URL is not a universal version for every Azure service. Before automating an operation, check its current REST reference, choose a supported stable version where possible, and test the request. If a script later fails, check the response and the provider's version support; version retirement is one possible cause, alongside permissions, policy, and changed resource state.

§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. Before you use it, it is worth seeing the whole request laid out, because a friendly command is only these five parts filled in for you.

The five parts of every ARM request

Strip away the tooling and every call to ARM is an ordinary HTTP request with the same five parts. Learn to name them and no CLI, SDK or template is a black box again — each is just assembling this and pressing send.

Table 1 — one ARM request, taken apart
PartExampleWhat it carries
MethodPUTThe verb — what you want done to the resource. See below.
URL path/subscriptions/…/providers/Microsoft.Storage/storageAccounts/campuxstoreThe resource ID from §2, reused verbatim as the route. The address is the path.
api-version?api-version=2023-01-01The required version stamp from §3. No default; omit it and the request is refused.
Authorization headerBearer eyJ0eXAi…The Entra bearer token that proves who is calling. Everything below §4 is about this line.
Body (JSON){ "location": "westeurope", "sku": … }The desired state, on PUT/PATCH only. A GET or DELETE carries no body.

The HTTP method says what kind of operation you request. GET reads; DELETE requests removal; a resource PUT commonly creates or updates the resource at a specified ID; and PATCH commonly updates selected fields. POST often invokes an action such as listKeys or restart. For the simple storage-account PUT in the game, sending the same valid request to the same ID does not create a second account. This is idempotency of that resource operation, not a guarantee that every deployment has no side effects or that a tool sends a PUT when nothing changed. Always read the particular operation's contract before retrying it.

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.

Where does the Bearer header come from? After you sign in, az rest uses your CLI identity to obtain a token for the target service and attaches it to the request. For an ARM URL, the token is for the ARM audience. You do not need to print, copy, paste, or upload a live token to learn this. Treat a bearer token like a password: anyone holding it may be able to act as its bearer until it expires.

GET https://management.azure.com/subscriptions/{subscription-id}/resourcegroups?api-version=2021-04-01
Authorization: Bearer [redacted by the CLI]

Predict, run, verify: predict that an authenticated az rest call to that ARM URL can list resource groups within your permissions. Run the read-only Lab 1 command, then check that the JSON contains resource-group names you recognize. The CLI handles the credential while you inspect the request's method, path, version, and response.

Three boundaries matter. First, an ARM token is meant for the ARM audience; a storage data-plane operation requires the right audience and its own authorization. Second, Azure checks authorization for management requests at the target scope, but role-assignment changes can take time to propagate; do not promise immediate revocation based on a screen update. Third, the Activity Log records management events, usually writes and actions rather than reads. It does not show each blob read. Azure retains Activity Log events for 90 days by default; configure export in advance if you need them longer.

Play

Play it through

Send a simulated storage-account PUT twice to the same resource ID and watch the account count stay at one. Then decide what that result proves, and where it stops applying.

§5

The Activity Log is a transcript of the API

Azure's Activity Log records management events such as resource changes, deployments, and service-health events. Entries commonly include the caller, time, target, and status. It does not capture every API call or the contents of every request. Use it as a first stop when a management operation fails.

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.

When a portal create or update fails, filter the Activity Log by time, resource, and status. Inspect the event's JSON and error details; they can point to a policy denial, permission, quota, or invalid setting. If the event has a correlation ID, use it to connect related operations. Some failures require the deployment operation details or the service's own logs, so keep the original error too.

One field repays learning by name: the correlation ID. A single portal action — deploying a VM, say — fans out into many ARM operations: the network interface, the disk, the VM itself. Azure stamps them all with one shared correlation ID, so when a deployment half-succeeds and leaves a mess, you filter the Activity Log to that one ID and read the whole chain in order, seeing exactly which sub-operation failed and what the ones before it had already created. This is also why "it failed" is rarely the useful question; "which operation in the chain failed, and what did it leave behind?" is the one that ends the outage. The Activity Log answers the second, and it answers it in the API's own words rather than a screen's summary — which is the entire argument of this class, written down as a debugging habit you will use every week you are employed.

Figure 3: one click, many operations, one correlation ID. A portal button labelled Create VM fans out into three ARM operations, PUT network interface, PUT disk and PUT virtual machine, each stamped in red with the same correlation ID. The three converge through one filter on that ID into the Activity Log, which lists the chain in order: network interface ok, disk ok, virtual machine failed. One click Create VM Many operations PUT network interface PUT disk PUT virtual machine first second third · fails 7f3a…c9 7f3a…c9 7f3a…c9 Activity Log filter: one ID 1 · nic — ok 2 · disk — ok 3 · vm — failed read in order one correlation ID — filter to it and the whole chain reads in order
Figure 3 One click is never one request. The portal composes several ARM operations — the network interface, the disk, the VM itself — and Azure stamps each with the same correlation ID before it runs. When the deployment half-succeeds, that stamp is the thread: filter the Activity Log to the one ID and the operations come back as a chain, in order, with the step that failed and everything the earlier steps had already created. "Which operation in the chain failed?" is a filter, not a mystery.
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

The game repeated a simulated PUT. Here you will make safe, read-only ARM requests, inspect a resource ID, and observe what happens when the required API version is missing. Creating a storage account is optional and costs money while it exists.

  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. Read the ID of a resource group you already have access to. This ID is shorter than the storage account in Figure 2:

    az group list --query "[].{name:name,resourceId:id}" --output table
    On screen: each ID ends after the resource-group name. If you have access to a storage account, open its JSON View in Lab 2 to see the longer resource-group-scoped example. No new Azure resources are required.
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, look for JSON View. If available, open it.On screen: the resource ID and JSON representation. A resource group has a short ID; a storage account has the longer shape in Figure 2. The exact fields depend on resource type and API version.

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

  4. If Download a template for automation is available on the review step, inspect it without deploying.On screen: an automation template representing the planned resource configuration. It is not the exact HTTP request the portal would send. Compare its resource type, name, location, and properties with the form.

  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 management event history and read a few operations. Ordinary reads and service data-plane actions are generally absent.

  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.

Think in systems

Zoom out: one API behind everything is one place to reason about all of it

You can read a resource ID. Now reason about what "everything is ARM" does to the whole estate, because a click is a request, and a request is something you can review, permission, and replay.

Feedback loops

Clicks in the portal feel free, so drift accumulates, so the running estate diverges from any record of why it looks the way it does. What turns clicks back into reviewable requests?

Dependencies & coupling

Every tool — portal, CLI, Terraform, the SDKs — depends on ARM; when it is slow or an api-version is retired, everything that speaks to it feels the same tremor.

The constraint

The resource-ID grammar is the ceiling on how you address, permission, and reason about anything; fluency in it is the most transferable skill in the class.

Second-order effects

Management changes leave event records you can inspect, but the Activity Log is not a complete replay of every request or data-plane action.

What breaks when it scales

An operation's supported API versions and fields can change. Review the current provider reference and test automation before an upgrade.

The engineer who ships is asked "does the portal do it?" The engineer who gets promoted is asked "and what request did the portal actually send?" — and could read it back.

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 each one is impractical. A script or infrastructure tool can use ARM to update those management properties at scale. First check the right resource IDs, permissions, and API operation; then test on a small set before applying the change to all three hundred.

Drill · The WhiteboardFrom memory · five minutes
Close the figures above. On paper, from memory, sketch how any Azure change happens — the clients, the one API, and the hierarchy it addresses. Five minutes. Draw the door, the nesting, and one request.

This is the whiteboard round of an interview. Rehearse it where it is cheap.

Mark your sketch — tick each your drawing got right:
The trap

Treating the portal as Azure itself is the mistake this class exists to kill. The portal just composes requests to ARM — and so do the CLI, Terraform, and the SDKs. If your sketch makes the portal special, you cannot explain how a script makes the same change, or how the Activity Log records it as an API call. Draw the portal as one client among several, all knocking on the same door, and the whole class snaps into place.

Class Sixteen

Examination

The Whiteboard above, four drills here, 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. This ARM REST request needs an api-version. The omitted-version call in Lab 1 shows the error. Choose a version supported by the particular operation; an older version is not automatically broken just because it is old.

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

Portal, CLI, and SDK management actions can use ARM; the Activity Log records management events; and az rest can attach a token for you. A blob read is a data-plane operation, so check the storage service's diagnostic logs if enabled. The other false statement fails because subscription-scoped resources need no resource-group segment, and higher-scope IDs have still different shapes.

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 canonical spelling is resourceGroups, but ARM treats path segments as case-insensitive — Lab 1 called /resourcegroups in lowercase and succeeded, so casing is convention, not 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.

Start with the Activity Log. Filter by time and Failed status, find the operation, and inspect its JSON and correlation ID. It may show a policy denial, quota problem, or permission failure. If the event only summarizes the failure, open the deployment operation details or the service's own logs before retrying.

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. Read a resource ID by scope. A storage account includes a subscription and resource group; other resources can have shorter or longer paths.
  3. An ARM REST request needs an API version supported by that operation. Check the provider's current reference before automating.
  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 records management events, not every API request. For a failed change, inspect its event and deployment details.
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." ↩