Coding 101

# Check here for code samples as you work through this lab

How to call REST APIs from Python

As part of the DevNet Zone sessions at Cisco Live US 2014, the DevNet team presented a Coding 101 session to help new developers, returning developers and NetOps engineers who are beginning to work with REST APIs.

This Coding 101 session explains the basics of consuming a REST API, and walks you through making your first REST API calls from Python. You can also watch the video of the full session presentation.

In the Cisco Live session, we also introduced the NeXt UI Toolkit. We are going to cover NeXt in a separate learning lab.

Sample code disclaimer

The examples and code in this presentation are for learning and educational purposes.

The samples were created with the goals of clarity and ease of understanding. If you are writing code for a real application, you would write the code in a more efficient and structured style.

Before you begin

You will need to download and setup a few items before you can begin coding along with us.

  1. Download the Coding 101 sample code
  2. Your favorite text editor (text wrangler, notepad ++, sublime text etc.)
  3. Postman Rest Client for Chrome
  4. Python
    • Python is normally pre-installed on Mac OS and most Linux distributions.
    • You can also install Python on Windows.
    • First, check see if you have Python installed on your system.
    • Go to your command prompt and type “python”.
    • If you get an error, follow the installations to install python for your system type from this page
  5. You will also need to install the Requests Library for Python.
    • This is a library that makes it very easy to call REST APIs.
    • Follow these instructions to install the Requests library.

So what is a REST web service?

What is a Web Service?

A web service is a way for two systems to communicate through a defined interface. There are two major types of Web Services Ð REST or SOAP.

What is a REST Web Service?

REST is an architecture style for designing networked applications. A REST web service is a web service that is as easy to call as making an HTTP request. RESTful interfaces often offer the CRUD (Create, Update, Delete) operations. If you want to know more about REST in general, this is a great REST tutorial.

What is so great about REST?

REST is easy to use on any platform

For this lab, we are going to use the pre-beta version of the soon to be released APIC-EM APIs.

The Application Policy Infrastructure Control (APIC) Enterprise Module (EM), Application Programming Interface (API), APIC-EM APIs, allows the deployment and execution of application policy across your networking infrastructure.

Using the the APIC-EM APIs, we can retrieve information about devices on our network including a list of Hosts, a list of Devices, a list of Policies and a list of configured Applications. We are going to use these features as examples to learn how to make REST calls from Python.

Take a look at the APIC-EM Reference Docs to see the details of all of the APIC-EM endpoints.

How does this work?

How It Works

REST is centered around the HTTP request and response model. Consuming an API is just as simple as making an HTTP request.

In this example, we request the list of Hosts, and that information is returned to us in the response. The data returned in the response is usually json or xml.

JSON – JavaScript Object Notation, is a lightweight text-based open standard designed for human-readable data interchange.

What do I need to know to make a Request?

To construct a request, you need to know the following information for the API that you are calling. You can find this information in a the API reference documentation.

What is in the Response?

REST in Action: Now let’s try it!

APIC-EM Example: Get Hosts

Let’s take a deeper look at the Get Hosts endpoint.

We need to know how to construct the request to retrieve the list of Hosts. So we need to use the API docs to determine the:

All of the urls for API-EM are in reference to:

http://server:8081/api/v0

To view the details of the Get Hosts endpoints from the APIC-EM API Docs open the api reference, and select Hosts in the left hand column, then choose /host.

GET /host/: returns information about all the hosts stored in the controller.

So that means that we will use the GET method, and the URL we will need to call to retreive a list of all of the hosts is:

http://server:8081/api/v0/host

We also need to know what kind of authentication to use.

APIC EM southbound interfaces that speak to individual network devices use the Cisco Command Line Interface (CLI), authentication is done using the CLI user name and password for each of the devices. The JSON objects that are posted via the REST API have key-value pairs that are the user names and passwords to be applied.

So you will use a user name, password pair that is configured on your system.

So to get the list of Hosts, our request will be like this:

Make a REST API Call

There are many HTTP clients that can help you quickly test web services.

We are going to use Postman as an example.

  1. Start Chrome and open Postman

  2. Now we, need to enter the information for our request into Postman:

    • Method
      • Select GET in the Method drop down
    • URL
      • Enter http://{APIC-EMController}/api/v0/hosts
    • Headers
      • not required for this request
    • Authentication
      • Basic HTTP Authentication using credentials configured on your system *Click Basic Auth tab and enter credentials
    • Body
      • not required for this request

  1. Click Send.
  2. Postman will send request to the server, and the display the response.
    • You can see the Response Code that is returned.
    • You can see the json that contains the list of hosts that is returned.

Give it a try with some of these other endpoints. You can look up each endpoint in the APIC-EM docs for more information.

To send data to a REST service and either create or update data, you will need to use POST or PUT.

Using the POST or PUT Method

POST /policy
{ 
"policyName":"IPTestPolicy", 
"policyOwner":"admin", 
"policyPriority":4095, 
"resource":{ 
"userIdentifiers":["server"], 
"applications":["SMTP"] 
}, 
"networkUser":{ 
"userIdentifiers":["tom"], 
"applications":["0,0,tcp"] 
}, 
"actions":["PERMIT"], 
"scope":"Segment1", 
"actionProperty":{"priorityLevel":11} 
} 

Doing a POST or a PUT is slightly more complicated because you need to send data in the Request body, and you also need to send the Content-Type header to indicate what type of data you are sending in the body.

Let’s look at the policy endpoint as an example. Open the api reference, and browse to the POST method for the /policy endpoint.

So our request to Create a Policy will be:

JSON lint is handy tool for validating JSON, and you can use it to help find errors in your json.

Now let’s try a POST

  1. Start Chrome and open Postman
  2. Now we, need to enter the information for our request into Postman:

    • Method
      • Select POST in the Method drop down
    • URL
      • Enter http://server:8081/api/v0/policy
    • Headers
      • Content-Type: application/json
    • Authentication
      • Basic HTTP Authentication using credentials configured on your system *Click Basic Auth tab and enter credentials
    • Body
      • json specifying policy
  3. Click Send.

  4. Postman will send request to the server, and the display the response.

    • You should see a 201 Created HTTP Response Status returned.

Using Postman (or any other REST Client) is a great way to explore, test and understand a REST API.

Next, we are going to look at how to call REST APIs from Python.

Setup your Python Environment

To get started writing some Python, you need to make sure you have the following tools on your system.

Here are some more sites that can help you setup python on your system.

Python Examples

First REST call from Python

# Simple Example of calling REST API from Python
# This is all that is required to call a REST API from python

import requests

# put the ip address or dns of your apic-em controller in this url
url = 'http://YOUR-APIC-EMController/api/v0/host'

# this statement performs a GET on the specified url
response = requests.get(url)

# print the json that is returned
print response.text

The code to the right makes a very simple GET request using the Requests library.

Let’s look at what the code is doing.

  1. First, we import the requests library.
  2. The next line creates a variable called url that contains the url we are going to use in the request.
  3. response = requests.get(url) makes a request to the specified url using the GET method. The response from the endpoint is returned to the variable called response.
  4. print response.text prints the json that was returned in the response to our screen.

That’s it. We made our first call to a REST endpoint from Python. Give it a try!

To run this code on your system:

  1. Copy and paste the code in the right panel into a text file.
  2. Insert your APIC-EM Controller IP address into the URL.
  3. Save the file with the extension .py. For example, apic-em1.py.
  4. Go to your command prompt, change to the directory where you saved the apic-em1.py file.
  5. Type python apic-em1.py at the command prompt, and hit return.
  6. The program should execute or display an error message.

If the program runs successfully, you will see the json that is returned displayed as text.

Next, we are going to build on the above simple example, and learn how to parse and use the json that is returned in the response.

apic-em-helloworld.py

# Getting started with APIC-EM APIs 
# First Call to APIC-EM REST API - "Hello World"

# import the requests library so we can use it to make REST calls (http://docs.python-requests.org/en/latest/index.html)
import requests

# All of our REST calls will use the url for the APIC EM Controller as the base URL
# So lets define a variable for the controller IP or DNS so we don't have to keep typing it
controller = "http://YOUR-APIC-EMController/"

# Get Devices
# This function allows you to view a list of all the devices in the network(routers and switches).
# Use our controller address plus the url for this API to construct the URL we need to call
get_devices_url = controller + 'api/v0/network-device'

# Send Request using GET Method and specify URL
# An object containing the response codes and json is returned.
get_devices_response = requests.get(get_devices_url)

# Print the response so we can see it.
print "Devices = "
print get_devices_response.text

We are going to use the following python samples. Download Samples

The first example, apic-em-helloworld.py, uses the network-device endpoint to retrieve a list of network devices, and it is very similar to the Get Hosts example above.

In this example, we define a variable called controller to hold the base url for our endpoints.

We can then use this variable to build the endpoint url. This variable is handy when we are making many API calls because we don’t have to keep typing the base url.

Here an example of what you should see when you run apic-em-helloworld.py.

learning-lab-basics.py

# Getting started with APIC-EM APIs 
# Follows APIC-EM Basics Learning Lab
# Hello World with JSON and pretty printing


# import the requests library so we can use it to make REST calls (http://docs.python-requests.org/en/latest/index.html)
import requests

# import the json library.  This provides many handy features for formatting, displaying
# and manipulating json.  https://docs.python.org/2/library/json.html
import json

# All of our REST calls will use the url for the APIC EM Controller as the base URL
# So lets define a variable for the controller IP or DNS so we don't have to keep typing it
controller_url = "http://YOUR-APIC-EMController/"

# Get Devices
# This function allows you to view a list of all the devices in the network(routers and switches).
get_devices_url = controller_url + 'api/v0/network-device'

#Perform GET on get_devices_url
get_devices_response = requests.get(get_devices_url)

# The json method of the response object returned by requests.get returns the request body in json format
get_devices_json = get_devices_response.json()

# json.dumps serializes the json into a string and allows us to
# print the response in a 'pretty' format with indentation etc.
print "Devices = "
print json.dumps(get_devices_json, indent=4, separators=(',', ': '))

In the previous examples, the json prints as one continuous text block that is really hard to read. Let’s pretty-print the json to make it more readable.

First, we need to import the json library. This library provides many useful methods for working with json.

Next, we make the API call as in the previous examples.

After, we get the response, we use the response.json() method to access the request body that is returned as a json object.

Then we use json.dumps() to print the json and specify the indentation that we want to use.

Here is an example of the output of learning-lab-basics.py. The JSON is much easier to read!

learning-lab-basics-step2.py

# Getting started with APIC-EM APIs 
# Follows APIC-EM Basics Learning Lab Step 2
# Get Devices and Print networkDeviceId values


# import the requests library so we can use it to make REST calls (http://docs.python-requests.org/en/latest/index.html)
import requests

# import the json library.  This library gives us many handy features for formatting, displaying 
# and manipulating json.
import json

# All of our REST calls will use the url for the APIC EM Controller as the base URL
# So lets define a variable for the controller IP or DNS so we don't have to keep typing it
controller_url = "http://YOUR-APIC-EMController/"

# Get Devices
# This function allows you to view a list of all the devices in the network(routers and switches).
get_devices_url = controller_url + 'api/v0/network-device'

#Perform GET on get_devices_url
get_devices_response = requests.get(get_devices_url)

# The json method of the response object returned by requests.get returns the request body in json format
get_devices_json = get_devices_response.json()

#Now let's read and display some specific information from the json

# set our parent as the top level response object
parent =  get_devices_json["response"]

print "Devices = "

# for each device returned, print the networkDeviceId
for item in parent:
         print item["networkDeviceId"]

In the previous examples, we retrieved a list of the network devices and displayed the json that was returned.

However, just displaying the json is not very useful. We need to learn how to parse the json and use specific values from the json.

For this example, we will parse the json and print out the list of all of the network device IDs for the devices that are returned.

Now, we can loop through all of the child items of the parent object, and print out the “networkDeviceId” value for each item.

Here is what you will see when you run learning-lab-basics-step2.py.

This same pattern can be used to access any of the values in the json. Give it a try!

learning-lab-basics-step3.py uses this same kind of logic to retrieve the lists of devices, applications, hosts and policies.

learning-lab-create-policy.py

# Getting started with APIC-EM APIs 
# Follows APIC-EM Basics Learning Lab
# Create a Policy Use Case
# Basic Steps
#   1. Get Hosts
#   2. Get Policies
#   3. Create Policy
#   4. Get Policies again to show new one that was added

# import the requests library so we can use it to make REST calls (http://docs.python-requests.org/en/latest/index.html)
import requests

# import the json library.  This library provides many handy features for formatting, displaying
# and manipulating json.
import json

# All of our REST calls will use the url for the APIC EM Controller as the base URL
# So lets define a variable for the controller IP or DNS so we don't have to keep typing it
controller_url = "http://YOUR-APIC-EMController/"


# Get Hosts
# This function allows you to view a list of all the hosts in the network.
get_hosts_url = controller_url + 'api/v0/host'

# Perform GET on get_hosts_url
r = (requests.get(get_hosts_url))

hosts_obj = r.json()

# For this example, we will use the IP Address of the second host in the list
hosts_parent =  hosts_obj["response"]
selected_host = hosts_parent[2]["hostIp"]

# Print the IP address of this host so we can see it.
print "\nThis is the selected host = ", selected_host


# Specify URL for policies
policies_url = controller_url + 'api/v0/policy'

# Perform GET on policies_url
policies_response = requests.get(policies_url)

# set our parent as the top level response object
policies_parent =  policies_response.json()

print "\nPolicies= "

# Print list of policies before we add the new one
# for each policy returned, print the policyID
for item in policies_parent["response"]:
         print item["policyId"]

# print total number of policies before we create the new one
print "Total number of policies before = ", len(policies_parent["response"])


# Create a new Policy
# We need to send JSON in the request to specify the attributes of our new policy.
# The combination of policyName, hostIp, and the ports must be unique for a new policy.

# This is the JSON we will use to
# {
#     "actions": [
#         "DENY"
#     ],
#     "policyName": "blockport1234",
#     "policyOwner": "Admin",
#     "networkUser": {
#         "userIdentifiers": [
#             "20.0.0.3"         # this is the HostIp
#         ],
#         "applications": [
#             "1234,1236,TCP"
#         ]
#     }
# }

# Create an object that holds our JSON to create a policy.
# Use our selected_host variable that is defined above to specify the hostIP
payload = {
    "actions": [
        "DENY"
    ],
    "policyName": "blockport1234",
    "policyOwner": "Admin",
    "networkUser": {
        "userIdentifiers": [
            selected_host
        ],
        "applications": [
            "1234,1519,TCP"
        ]
    }
}


# To create a policy, we need to use the POST method.
# When using POST, you need to specify the Content-Type header as application/json
headers = {'content-type': 'application/json'}

# Use requests.post to do a POST to the policy API
# Specify request body json data and headers
policy_response = requests.post(policies_url, data=json.dumps(payload), headers=headers)

print "\nResult of Create", policy_response.text


# Display list of policies after our new addition
get_policies_url = controller_url + 'api/v0/policy'

# Perform GET on policies_url
policies_response = requests.get(get_policies_url)

# set our parent as the top level response object
policies_parent =  policies_response.json()

print "\nPolicies= "

# print list of policies after the new policy was added.
# for each policy returned, print the policyID
for item in policies_parent["response"]:
         print item["policyId"]

# print total number of policies after we created the new policy
print "Total number of policies after = ", len(policies_parent["response"])

In this example, we will look at how to do a POST to create a policy.

We are going to use the ideas from the examples above to create a simple application that:

  1. Gets a list of Hosts
  2. Gets the IP address of the second host in the list
  3. Gets as list of Policies and displays the current number of Policies
  4. Creates a new Policy
  5. Gets the list and count of Policies again to show that a new policy was added

1. Get a list of Hosts

The code for this is the same code we used in the previous examples to retrieve the list of Hosts.

2. Gets the IP address of the third host in the list

selected_host = hosts_parent[2]["hostIp"] creates a variable called selected_host and populates this variable with the hostIp value for the 3rd host in our list of hosts. In a “real application”, you would probably have the user select the host, but we are going to just use the 3rd one in the list to keep this example simple.

3. Gets a list of the policies and display the count of policies

First, we use the code from the previous examples, policies_response = requests.get(policies_url) to do a GET and retrieve the list of policies. Then we parse the json, and print out the policeId of each policy.

for item in policies_parent["response"]:

print item["policyId"]

We also get the number of policies in the policy array and print that number. len(policies_parent["response"])

To create a policy, we need to do a POST and send json in the request body that specifies the policy we want to create.

We create an object called payload that holds the json we are going to send in the body.

We also create a variable that we will use to specify the Content-Type header in our request. headers = {'content-type': 'application/json'}

And finally, we pass the headers object and our payload object to the post method of requests to make the request.

policy_response = requests.post(policies_url, data=json.dumps(payload), headers=headers)

To display the new policy, we use the same code as above to loop through the policies and display the Ids.

for item in policies_parent["response"]:

print item["policyId"]

Here is an example run of learning-lab-create-policy.py.

Give it a try!

Summary

Now, you have the basics for making REST calls from Python. You can use these techniques with any REST API. Experiment, learn, have fun, make something cool!

If you have questions or comments, please join in the conversation in our DevNet Community and follow us on Twitter @CiscoDevNet.

Download the Sample Code

Watch the Video

References