Understanding and Using APIs · Topic 7 of 7

Calling a REST API with the Requests Library

Write a Python script that calls a REST API with the requests library, using get, post, headers, params, json, timeouts, status checks and a Session.

  • 4 min
In a nutshell
  • The function name matches the method: get, post, put, patch, delete.
  • headers and params take dictionaries, and params builds the query string.
  • json= sends a dictionary as JSON, and response.json() parses a JSON reply.

What it is

The requests library is the standard third party Python package for sending HTTP requests.

It turns the parts of a request into function arguments and the parts of a response into attributes. A few lines of code replace a lot of low level work.

You install it with pip install requests, then import it in your script.

Scriptrequests.get or postheaders, params, jsonAPIREST serviceResponse objectScriptstatus, headers, body

How it works

You call a function named after the method, then read the Response object that it returns.

The basic functions

FunctionHTTP method
requests.get()GET
requests.post()POST
requests.put()PUT
requests.patch()PATCH
requests.delete()DELETE

Useful arguments

ArgumentPurpose
headersA dictionary of request headers
paramsA dictionary that becomes the query string
jsonA dictionary sent as a JSON body, with Content-Type set for you
dataA form encoded or raw body
authA tuple of username and password for basic authentication
timeoutSeconds to wait before giving up
verifyWhether to check the server certificate. It defaults to True

The Response object

Attribute or methodMeaning
status_codeThe numeric status, such as 200
okTrue when the status is below 400
headersThe response headers, as a dictionary like object
textThe body as a string
json()The body parsed as JSON
raise_for_status()Raises an exception for a 4xx or 5xx code

A complete script

This script lists devices from a fictional API, with an API key held in an environment variable.

import os
import requests

BASE_URL = os.environ["API_BASE"]
API_KEY = os.environ["API_KEY"]

headers = {
    "Authorization": "Bearer " + API_KEY,
    "Accept": "application/json",
}
params = {"limit": 20}

try:
    response = requests.get(
        BASE_URL + "/v1/devices",
        headers=headers,
        params=params,
        timeout=10,
    )
    response.raise_for_status()
except requests.exceptions.RequestException as err:
    print("Request failed:", err)
else:
    for device in response.json()["items"]:
        print(device["name"], device["status"])

The try block catches network problems and bad status codes. The else block runs only when the call worked.

Creating a resource with POST

payload = {"name": "edge-sw1", "site": "London"}

response = requests.post(
    BASE_URL + "/v1/devices",
    headers=headers,
    json=payload,
    timeout=10,
)
print(response.status_code)
print(response.json())

Because json=payload is used, there is no need to call json.dumps() yourself.

Updating and deleting

requests.put(BASE_URL + "/v1/devices/42", headers=headers, json=payload)
requests.delete(BASE_URL + "/v1/devices/42", headers=headers)

A successful DELETE often returns 204 with no body, so do not call .json() on it.

Sessions

A requests.Session object keeps settings and the connection across calls. This saves repeating the same headers.

session = requests.Session()
session.headers.update(headers)

devices = session.get(BASE_URL + "/v1/devices", timeout=10)
sites = session.get(BASE_URL + "/v1/sites", timeout=10)

Certificates and the verify argument

By default, requests checks the server certificate. Lab devices often use self signed certificates, which makes the call fail.

Setting verify=False turns the check off and works in a lab. It removes protection against impostors, so avoid it in production. A better fix is to point verify at the right certificate file.

Common error types

  • requests.exceptions.ConnectionError when the server cannot be reached.
  • requests.exceptions.Timeout when the server did not answer in time.
  • requests.exceptions.HTTPError when raise_for_status() sees a 4xx or 5xx code.
Exam tip

Always set a timeout. Without one, a call to an unresponsive server can wait for a very long time.

What to remember for the exam

Seven facts cover this topic.

  • The function name matches the method: get, post, put, patch, delete.
  • headers and params take dictionaries, and params builds the query string.
  • json= sends a dictionary as JSON, and response.json() parses a JSON reply.
  • status_code holds the code and raise_for_status() raises on 4xx and 5xx.
  • auth=(user, password) gives basic authentication.
  • timeout stops a call waiting forever.
  • A Session reuses headers and the connection across calls.

Common mistakes

Four mistakes are typical.

Calling .json() on an empty body. A 204 response has no body, so parsing it raises an error.

Forgetting the timeout. The script may hang.

Using data= when the API wants JSON. Use json= so that the body and Content-Type are correct.

Leaving verify=False in production code. It disables certificate checking.

Watch out

A response with status 404 or 500 does not raise an exception by itself. Check status_code or call raise_for_status().

Check yourself

Work through these three questions.

  • Which argument sends a Python dictionary as a JSON body?

    The json argument, for example requests.post(url, json=payload).

  • How can you make a script stop on a 4xx or 5xx reply?

    Call response.raise_for_status(), which raises an exception for those codes.

  • Why should every call have a timeout?

    Without a timeout, a call to an unresponsive server can wait for a very long time.

Topic 7 of 7 in Understanding and Using APIs

Test yourself on Understanding and Using APIs

The full Cisco CCNA 200-901 DEVASC question bank has 808 questions, with timed practice exams and an explanation for every answer.

This study guide is independent and is not affiliated with, endorsed by, or sponsored by Cisco. Vendor names, certification names and exam codes are trademarks of their respective owners and are used for identification only.