REST APIs, requests.get, tokens, query parameters & JSON

Ask the inventory API

Lesson 16 of 20 · 14 min · Module 5: APIs and the source of truth

Large networks keep their inventory in a source of truth such as NetBox: one place that says which devices exist, where they are and how to reach them. Scripts ask it over a REST API instead of reading a spreadsheet.

Start this lesson →

Free. No installation: you write and run the code in your browser, and it is checked automatically.

By the end, you’ll be able to…

  • Call a REST API with requests
  • Authenticate with a token header
  • Read nested JSON fields

The idea

requests.get(url, headers=..., params=...) sends an HTTP GET. NetBox expects the header Authorization: Token <token>; without it the answer is 403 Forbidden. params={"site": "bucharest"} becomes ?site=bucharest and filters on the server. response.raise_for_status() raises an error for 4xx and 5xx answers, and response.json() returns the body as Python data: a list endpoint answers with count, next, previous and results. The practice API at https://inventory.lab works like NetBox; its address and a token are in INVENTORY_URL and INVENTORY_TOKEN.

import os
import requests

URL = os.environ["INVENTORY_URL"]
HEADERS = {"Authorization": f"Token {os.environ['INVENTORY_TOKEN']}",
           "Accept": "application/json"}

response = requests.get(f"{URL}/api/dcim/sites/", headers=HEADERS)
response.raise_for_status()
print([site["name"] for site in response.json()["results"]])

01No token, no data

The API answers, but refuses. The status code and the JSON body say why.

import os
import requests

URL = os.environ["INVENTORY_URL"]
response = requests.get(f"{URL}/api/dcim/devices/")
print(response.status_code)
print(response.json())
Output
403
{'detail': 'Authentication credentials were not provided.'}

02With the token

count is the number of matching devices; results holds one page of them, and next is the link to the following page.

HEADERS = {"Authorization": f"Token {os.environ['INVENTORY_TOKEN']}",
           "Accept": "application/json"}
data = requests.get(f"{URL}/api/dcim/devices/", headers=HEADERS).json()
print(data["count"], len(data["results"]))
print(data["next"])
Output
6 5
https://inventory.lab/api/dcim/devices/?limit=5&offset=5

03Nested fields

Related objects come as small dictionaries. Each step of the path is one more key.

device = data["results"][0]
print(device["name"], device["site"]["slug"], device["platform"]["slug"])
print(device["primary_ip4"]["address"])
print(device["status"])
Output
core1 bucharest cisco_ios
10.0.0.1/24
{'value': 'active', 'label': 'Active'}

Your turn

Ask /api/dcim/devices/ for the devices in the Bucharest site (filter with site=bucharest). Build bucharest: a list of (name, address) tuples in the order the API returns them, where the address is the primary IPv4 address without the prefix length (10.0.0.1, not 10.0.0.1/24). Read the URL and the token from the environment.

What the checks look for

  • bucharest lists the four Bucharest devices
  • Sent the token and got 200 OK
  • Filtered on the server with site=bucharest
  • The token is not written in the code
Try it in the editor →

Take this with you

Ask the source of truth: GET with a token, check the status, read the JSON.

Go a little further

Also ask for role=access, and print the names that appear in both answers.

Learn Network Automation for free

20 short lessons with real code and instant checks.

See the whole course →