Quick answer: A REST API lets you manage a network device or controller by sending ordinary HTTP requests โ GET to read, POST to create, PUT/PATCH to update, DELETE to remove โ to URLs that represent resources such as interfaces, VLANs or routes. The device answers with JSON and a status code, so a few lines of Python using the requests library can replace hours of manual CLI work.
You will learn how REST works, how to authenticate against real network platforms, how to read and change configuration with Python, and how to avoid the errors that trip up most engineers early on. All examples run against Cisco’s free DevNet sandboxes, so no lab hardware is required.
What makes an API “RESTful”?
REST (Representational State Transfer) is an architectural style, not a product. An API is RESTful when it follows a handful of conventions:
- Everything is a resource with a URL.
/api/v1/interfaces/GigabitEthernet1represents one interface;/api/v1/vlansrepresents the collection of VLANs. - Standard HTTP methods express intent. The verb, not the URL, says whether you are reading or writing.
- Stateless requests. Each call carries everything the server needs (usually a token). The server does not remember your previous call.
- Structured representations. Data travels as JSON (occasionally XML), which maps directly to Python dictionaries and lists.
If you are new to APIs in general, start with Introduction to APIs: Unlocking the Power of Network Automation and come back here.
HTTP methods and status codes you must know
| Method | What it does | Network example | Typical success code |
|---|---|---|---|
GET |
Read a resource; never changes anything | Fetch all interfaces | 200 OK |
POST |
Create a new resource (server picks the ID) | Add a new VLAN | 201 Created |
PUT |
Replace a resource entirely | Overwrite an interface config | 200 or 204 No Content |
PATCH |
Update only the fields you send | Change just the description | 200 or 204 |
DELETE |
Remove a resource | Delete a loopback | 204 No Content |
On the error side, 400 means your payload is malformed, 401 means missing or wrong credentials, 403 means you are authenticated but not allowed, 404 means the resource or URL does not exist, 429 means you exceeded a rate limit, and anything in the 500s is the device’s fault. Your script should check the code on every call.
Authentication on real network platforms
Three schemes cover almost every device you will meet:
- HTTP Basic โ username and password sent (base64-encoded) in each request. Used by RESTCONF on Cisco IOS-XE and Juniper. Only ever over HTTPS.
- Token in a header โ a long-lived API key, for example Meraki’s
X-Cisco-Meraki-API-Keyor Arista CloudVision’s bearer token. - Login then token โ you
POSTcredentials to an auth endpoint, receive a short-lived token, and send it asX-Auth-TokenorAuthorization: Beareron later calls. Cisco DNA Center, Palo Alto Panorama and most cloud platforms work this way.
Hands-on: reading and writing with Python requests
Install the library with pip install requests. The examples use Cisco’s always-on IOS-XE RESTCONF sandbox; check the DevNet site for the current hostname and password.
Example 1 โ a reusable session and a GET with query filtering:
import requests
from requests.auth import HTTPBasicAuth
BASE = "https://sandbox-iosxe-latest-1.cisco.com/restconf/data"
session = requests.Session()
session.auth = HTTPBasicAuth("admin", "C1sco12345")
session.headers.update({
"Accept": "application/yang-data+json",
"Content-Type": "application/yang-data+json",
})
session.verify = False # sandbox uses a self-signed certificate
# Only return the fields we care about
params = {"fields": "interface(name;description;enabled)"}
resp = session.get(f"{BASE}/ietf-interfaces:interfaces", params=params, timeout=15)
resp.raise_for_status()
for intf in resp.json()["ietf-interfaces:interfaces"]["interface"]:
print(f'{intf["name"]:<20} {intf.get("description", "-"):<35} up={intf["enabled"]}')
A Session remembers authentication and headers, reuses the TCP connection, and keeps the rest of your code short. The fields query parameter asks the device to send only three attributes, which is far faster than pulling the whole interface tree.
Example 2 โ change a description with PATCH, then verify:
intf_url = f"{BASE}/ietf-interfaces:interfaces/interface=GigabitEthernet2"
patch_body = {
"ietf-interfaces:interface": {
"name": "GigabitEthernet2",
"description": "Uplink to core - managed by Python",
}
}
resp = session.patch(intf_url, json=patch_body, timeout=15)
print("PATCH status:", resp.status_code) # expect 204
check = session.get(intf_url, timeout=15).json()
print("Now reads:", check["ietf-interfaces:interface"]["description"])
Example 3 โ a login-then-token flow with proper error handling (Cisco DNA Center style):
import os
import requests
from requests.auth import HTTPBasicAuth
from requests.exceptions import HTTPError, Timeout, ConnectionError
DNAC = "https://sandboxdnac.cisco.com"
USER = os.environ.get("DNAC_USER", "devnetuser")
PASS = os.environ["DNAC_PASS"] # fail fast if not set
def get_token() -> str:
r = requests.post(f"{DNAC}/dna/system/api/v1/auth/token",
auth=HTTPBasicAuth(USER, PASS), timeout=15)
r.raise_for_status()
return r.json()["Token"]
def list_devices(token: str) -> list[dict]:
r = requests.get(f"{DNAC}/dna/intent/api/v1/network-device",
headers={"X-Auth-Token": token}, timeout=15)
r.raise_for_status()
return r.json()["response"]
try:
devices = list_devices(get_token())
for d in devices:
print(f'{d["hostname"]:<25} {d["managementIpAddress"]:<16} {d["softwareVersion"]}')
except HTTPError as e:
print("API returned an error:", e.response.status_code, e.response.text[:200])
except (Timeout, ConnectionError) as e:
print("Could not reach the controller:", e)
This pattern โ small functions, a token obtained once, explicit exception handling โ scales from a 20-line script to a full automation toolkit. The same structure works for Meraki, Arista CloudVision, Palo Alto, Fortinet and public clouds; only the URLs and header names change.
REST versus RESTCONF versus NETCONF
Many engineers mix these up. REST is the general style; each vendor designs its own URLs and payloads. RESTCONF is REST constrained by YANG data models, so the URL and JSON structure for an interface are defined by standards (RFC 8040) and look the same across vendors. NETCONF uses the same YANG models but runs XML over SSH and adds transactions โ candidate configs, validation, commit and rollback. Use REST for controllers and cloud, RESTCONF for quick per-device reads and writes, and NETCONF when you need an all-or-nothing config change.
Seven REST API mistakes to avoid
- Not checking the status code. A 401 still returns a body; if you call
.json()and index into it blindly you will chase phantom bugs. Useraise_for_status(). - Forgetting the
timeout. Without it,requestswaits forever on an unreachable device and your overnight job hangs. - Hard-coding passwords and keys. Pull them from environment variables, a
.envfile excluded from Git, or a vault. - Using
PUTwhen you meantPATCH.PUTreplaces the whole resource; sending only a description can erase the IP address. - Leaving
verify=Falsein production. It silently disables certificate checks and invites man-in-the-middle attacks. Trust the device’s CA instead. - Ignoring pagination. Controllers return results in pages (often 500 or 1,000 at a time). Follow the
nextlink or offset parameter or you will miss devices. - Running untested writes on production. Try every
POST,PUTandDELETEin a sandbox or virtual lab first.
Frequently asked questions
Can I use REST APIs on older switches that only have a CLI?
Not directly. For those devices use Netmiko or NAPALM over SSH, or put a controller in front of them that exposes a REST API. Many teams run both approaches during a migration.
Is requests the only option in Python?
No. httpx offers the same interface plus async support, which is useful when polling hundreds of devices concurrently. Vendor SDKs such as the meraki or dnacentersdk packages wrap the REST calls for you. Learning raw requests first makes all of them easier.
How do I explore an API before writing code?
Use the vendor’s interactive documentation (Swagger/OpenAPI pages), Postman, or plain curl. Once a call works there, translating it into Python takes a minute.
Key takeaways
- REST maps network resources to URLs and uses HTTP verbs to read, create, update and delete them.
- Always inspect status codes, set timeouts and keep credentials out of code.
- Use a
requests.Session, small functions and explicit exception handling to write scripts you can trust. - Know the difference between REST, RESTCONF and NETCONF so you pick the right tool for each change.
Ready to build real automation projects with Python? The Techknowledgehub Python & Data Science course takes you from Python basics through REST APIs, JSON handling and data pipelines, with mentor-led live classes and placement support. You can also follow our tutorials on the YouTube channel.



