APIs and REST for Network Engineers
Authentication and the Read/Write Safety Boundary
What you'll learn
- How token-based authentication headers work, conceptually
- Why credentials never belong in source code, the same rule as every prior module
- What POST/PUT/PATCH/DELETE are for, and why they need explicit review
- How this maps directly onto dry_run=True and --check from earlier modules
Listen to a guided explanation of this lesson.
Spoken narration isn't supported in this browser.
Token-based authentication
Most real APIs require proving who's asking, usually via a header carrying a token:
import requests
headers = {"Authorization": "Bearer demo-token"}
response = requests.get("http://127.0.0.1:8765/devices/SW1/vlans", headers=headers)
print(response.status_code)headers={} attaches extra metadata to the request — Authorization: Bearer <token> is the most common convention for API tokens. This module's mock API doesn't require this header for GET requests; it's shown here because POST requests below do.
Never hardcoded — the same rule since Netmiko Fundamentals
A token is a credential, exactly like the username/password Netmiko Fundamentals taught to source only from getpass()/input()/environment variables — never typed directly into a script. Every example in this lesson uses an obvious placeholder token ("demo-token") against a safe local mock, precisely the same discipline "Connecting to a Device with Netmiko" established for SSH credentials.
GET is safe; everything else needs a second thought
- Read-only, by conventionnever changes anything
- Safe to call freelythe default posture
- Creates, replaces, updates, or removes something
- Requires the same explicit review as send_config_set() / ios_config
A POST request, against the safe local mock only
new_vlan = {"id": 40, "name": "GUEST"}
headers = {"Authorization": "Bearer demo-token"}
response = requests.post(
"http://127.0.0.1:8765/devices/SW1/vlans",
json=new_vlan,
headers=headers,
)
print(response.status_code)
print(response.json())json=new_vlan does two things: sets the Content-Type header to application/json, and serializes the dict into the request body — the POST equivalent of a Jinja2-rendered config block, sent as structured data instead of CLI text.
201
{'hostname': 'SW1', 'created': {'id': 40, 'name': 'GUEST'}}Real, verified output — 201 Created (not 200) is the conventional status code for a successful POST that created something new. Run only against this module's safe local mock, never against a real controller by default.
What happens without the right credentials
response = requests.post(
"http://127.0.0.1:8765/devices/SW1/vlans",
json={"id": 40, "name": "GUEST"},
# no Authorization header this time
)
print(response.status_code)
print(response.json())The exact same request as before, minus the Authorization header.
401
{'error': 'authentication required'}Real, verified output. Exactly the response this module's mock API is built to give for any POST without valid credentials — mutation requires proving who's asking, GET does not.
The direct mapping to what this curriculum already taught
Same principle, new vocabulary
dry_run=True (Reliable Automation) and --check (Ansible) both exist so a mutating action can be previewed before it's real. This module's version of that same principle is simpler: GET first, always, to see current state, before ever constructing a POST/PUT/PATCH/DELETE — and never send one against a real controller without knowing exactly what it will do.
Key takeaways
- Authorization: Bearer <token> is the common convention for API authentication — a real credential, sourced the same way every credential has been since Netmiko Fundamentals: never hardcoded.
- GET stays the safe default; POST/PUT/PATCH/DELETE require the same explicit-review discipline as send_config_set()/ios_config.
- requests.post(url, json=data, headers=...) sends a JSON body with authentication — verified directly, including what a missing header (401) and a malformed body (400) each look like.
- This module's mutation examples run only against the safe local mock — the same dry_run=True/--check principle from earlier modules, applied to HTTP.