Skip to main content
PacketMentor logo
Open menu
← All topics
Automation & Programmability Foundational

Python requests: Your First REST Script

The Python requests library covers 95% of what network engineers need to call REST APIs: GET, POST, auth, JSON, status checks. 20 lines of code and you are done.

Quick summary
  • requests.get(url) returns a Response object. r.status_code is the integer. r.json() parses the body. r.text is the raw body string.
  • POST / PUT / PATCH / DELETE take the same keyword arguments: json=... for a JSON body, headers=... for a dict of request headers, auth=(user, pass) for basic auth, params=... for query string.
  • Call r.raise_for_status() right after the request to turn any 4xx or 5xx into a Python exception. Catches hidden failures.

Mental model

The Python requests library is the standard way to call REST APIs from Python. It wraps the HTTP machinery (sockets, TLS, redirects, encoding) so your code reads like English:

import requests

r = requests.get("https://api.example.com/devices")
print(r.status_code)
print(r.json())

Cisco objective 2.9 says “Construct a Python script that calls a REST API using the requests library”. That is this topic.

The Response object

Every request returns a Response. Four attributes do 90% of the work.

Attribute / methodWhat it isExample value
r.status_codeHTTP status as int200
r.reasonHTTP status phrase as str'OK'
r.textResponse body as str'{"ok":true}'
r.json()Response body parsed as dict/list (if JSON){"ok": True}
r.headersResponse headers as a case-insensitive dict{"Content-Type": "application/json", ...}
r.okTrue if 200 <= status_code < 400True
r.urlFinal URL after redirects'https://api.example.com/devices'

Call r.raise_for_status() right after the request to make any 4xx or 5xx throw. Otherwise your script keeps going on a 500 and prints junk.

GET

import requests

r = requests.get("https://api.example.com/devices")
r.raise_for_status()
data = r.json()
for d in data["devices"]:
    print(d["name"], d["ip"])

Query parameters

Two equivalent ways:

# In the URL
r = requests.get("https://api.example.com/devices?limit=10&offset=20")

# As a dict (requests URL-encodes them for you)
r = requests.get("https://api.example.com/devices", params={"limit": 10, "offset": 20})

Prefer the dict version. It handles special characters correctly.

Headers

r = requests.get(
    "https://api.example.com/devices",
    headers={
        "Authorization": "Bearer eyJhbGci...",
        "Accept": "application/json",
    },
)

JSON body (POST / PUT / PATCH)

r = requests.post(
    "https://api.example.com/devices",
    headers={"Authorization": "Bearer eyJhbGci..."},
    json={"name": "sw3", "ip": "10.0.0.3"},
)
r.raise_for_status()
print(r.json()["id"])

json= is the magic kwarg: requests sets Content-Type: application/json for you and encodes the dict as JSON. Compared to data=json.dumps(...) + manual header setting, this is one less thing to get wrong.

Basic auth

r = requests.get(
    "https://api.example.com/secure",
    auth=("admin", "cisco123"),
)

requests base64-encodes the credentials and sets the Authorization: Basic ... header for you.

Full example: list and create

import requests

BASE = "https://api.example.com/api/v1"
HEADERS = {"X-API-Key": "your-key-here"}

# List
r = requests.get(f"{BASE}/devices", headers=HEADERS)
r.raise_for_status()
print(f"{len(r.json())} devices known")

# Create
new_device = {"name": "sw3", "ip": "10.0.0.3"}
r = requests.post(f"{BASE}/devices", headers=HEADERS, json=new_device)
r.raise_for_status()
print(f"created device id = {r.json()['id']}")

20 lines. That is a working automation script, ready to loop over an input file.

Hands-on lab · 6 minute walkthrough

requests.get, .post, .json(), raise_for_status

10 steps in the Python REPL: import requests, GET a devices endpoint, read status and body, POST with json=, add headers={}, use auth=().

Open the lab →
python-requests · lab
>>> import requests
>>> r = requests.get("https://api.example.com/devices")
>>> r.status_code
200
>>>

FAQ

Why not use the built-in urllib? You can, and the stdlib urllib.request works. requests is three times less code for every realistic API call, handles auth and JSON for free, and is the de-facto standard everyone else writes about.

httpx or aiohttp? httpx is a modern alternative with the same API plus async support. aiohttp is async-first. requests is still the one 95% of tutorials and Cisco DevNet samples use; learn it first.

My script hangs forever. Pass timeout=5 (seconds). Without it, requests waits indefinitely. In production, always set a timeout.

How do I upload a file? requests.post(url, files={"file": open("x.txt", "rb")}). Not on 200-901 but useful to know.

Master this on a real network

Want this drilled into reflex?

1:1 weekly sessions, live feedback on your labs, and US interview prep: built around the CCNA Automation® exam blueprint. Free first session. No card on file until you decide.

Claim my free session →

Get the free CCNA 12-week roadmap

You're already reading up on Python requests: Your First REST Script. The roadmap is the order I recommend studying every CCNA topic in: with what to lab each week and where Python requests: Your First REST Script fits. A written personal reply, not an autoresponder. Expect it within one business day.

Personal reply from a senior network engineer. No third-party tracking. Unsubscribe any time.