Skip to content

Cisco APIs and wingpy

Detailed REST API theory can be found in the REST API section.

What is wingpy?

wingpy is a simple Cisco API client for Python, built for network engineers by Wingmen Solutions.

All Cisco APIs differ in how they handle authentication, session management, rate limiting, path construction, pagination and concurrency. With wingpy you don't need to worry about all of the complexities.

Although many Cisco platforms have dedicated SDKs, each of them is designed and maintained individually and have notable differences. With wingpy, just start coding and interact directly with API endpoints! This makes it much easier to work with new Cisco platform APIs and automate across domains.

Plenty of examples and explanations are available in the User Guide

Response Format and Body

Wingpy makes use of the httpx library, which is a powerful HTTP client for Python. It provides an easy-to-use interface for making HTTP requests and handling responses. It's return type, the Response object, is similar to the one provided by the popular requests library. It includes methods for accessing the response content, headers, status code, and more.

Using Cisco APIs in Python with wingpy

Below are examples of how to use wingpy to perform common API operations with Cisco Catalyst Center.

Authentication and Token Retrieval

Wingpy handles authentication and token retrieval automatically when you create an instance of the many clients availble. You just need to provide your credentials.

Authentication with wingpy
from getpass import getpass
from pprint import pprint

import wingpy

base_url = "https://sandboxdnac.cisco.com"

# link to CC Always On Sandbox API Documentation: https://sandboxdnac.cisco.com/dna/platform/app/consumer-portal/developer-toolkit/apis

# credentials
username = "devnetuser"
password = getpass()

# -- SESSION --
with wingpy.CiscoCatalystCenter(
    base_url=base_url,
    username=username,
    password=password,
    verify=False,
) as catalyst:

The code above imports the necessary libraries, including wingpy. It then sets the base URL for the API and prompts the user for their credentials. Finally, it creates a session object using the CiscoCatalystCenter class from wingpy, which handles authentication and token retrieval automatically during the first request. So the above code doesn't actually make any requests yet, but prepares the session for future requests.

Notice the use of a context manager (with statement) to ensure that the session is properly closed after use. Be sure to indent all code that uses the catalyst session object inside the with block.

Making API Requests

In Catalyst Center devices and interfaces are represented as objects. They have a dedicated endpoint for each object type. Sometimes you need to represent the interfaces of a device, so let's look at how to get a list of devices and their interfaces.

Get Devices and Interfaces with wingpy
    interface_url = "/dna/intent/api/v1/interface"
    device_url = "/dna/intent/api/v1/network-device"

    # get the interfaces
    interfaces = catalyst.get_all(interface_url)

    # devices list
    devices = catalyst.get_all(device_url)

The code is indented inside the with block to ensure it uses the catalyst session object.

The code above uses the get_all method of the catalyst object to retrieve a list of interfaces and devices from the API. The get_all method handles pagination automatically, so you don't need to worry about it. You just need to provide the endpoint URL for the object type you want to retrieve.

Processing and Printing the Data

Let's pretend we want to print the hostname and the Vlan1 interface IP address of each device. We need to create a mapping of device IDs to hostnames, then we can loop through the interfaces and print the desired information.

Before that, we filter the list of interfaces to only include those that start with "Vlan".

We don't need to indent this code, as it is outside the with block, since we don't need to make any more API requests. This means the session is already closed.

Filter Vlan Interfaces
# create a list of vlan interfaces
vlan_interfaces = []

for interface in interfaces:
    if interface["portName"].startswith("Vlan"):
        vlan_interfaces.append(interface)

Great! Now we can create a mapping of device IDs to hostnames.

Mapping Device IDs to Hostnames
for interface in vlan_interfaces:
    # get the device name from the devices list
    # we only have the device_id and have to look
    # through the devices list to find the hostname
    # since we are looking for a human readable output
    for device in devices:
        if device["id"] == interface["deviceId"]:
            device_name = device["hostname"]
            # stop the loop when we get a match!
            break
    # finally print the desired information
    print(device_name, interface["portName"], interface["ipv4Address"])

Alright, that was pretty straightforward! We used wingpy to handle authentication, token retrieval, and pagination. We then made API requests to get a list of devices and interfaces, filtered the interfaces to only include those that start with "Vlan", created a mapping of device IDs to hostnames, and finally printed the hostname and Vlan1 interface IP address of each device.

We could make the output a bit prettier, let's define a template:

Output Template
output_template = """ 
Device Name: {device_name}
Port Name:   {portname}
IP Address:  {ip_address}
"""

Now we can use the output_template to format our output in a more readable way. We can use the format method of the string to replace the placeholders with the actual values.

Pretty Output
for interface in vlan_interfaces:
    # get the device name from the devices list
    # we only have the device_id and have to look
    # through the devices list to find the hostname
    # since we are looking for a human readable output
    for device in devices:
        if device["id"] == interface["deviceId"]:
            device_name = device["hostname"]
            # stop the loop when we get a match!
            break

    # get the remaining two
    interface_ip_address = interface["ipv4Address"]
    interface_portname = interface["portName"]

    # format the message with data from the interface and the device name
    status = output_template.format(
        device_name=device_name,
        portname=interface_portname,
        ip_address=interface_ip_address,
    )

    # print the message
    print(status)

All The Code Together

Full Code Example
Full Example Code
from getpass import getpass

import wingpy

wingpy.set_logging_level("ERROR")

# SET A BASE URL
BASE_URL = "https://sandboxdnac.cisco.com"

interface_url = "/dna/intent/api/v1/interface"
device_url = "/dna/intent/api/v1/network-device"

# credentials
username = "devnetuser"
password = getpass() or "Cisco123!"

# define the message template to print on the console
# when we have multiple messages to print the .format()
# string method can be useful for readability.
output_template = """ 
Device Name: {device_name}
Port Name:   {portname}
IP Address:  {ip_address}
"""

# create a session
with wingpy.CiscoCatalystCenter(
    base_url=BASE_URL,
    username=username,
    password=password,
    verify=False,
) as catalyst:

    # get the interfaces
    interfaces = catalyst.get_all(interface_url)

    # devices list
    devices = catalyst.get_all(device_url)

# create a list of vlan interfaces
vlan_interfaces = []

for interface in interfaces:
    if interface["portName"].startswith("Vlan"):
        vlan_interfaces.append(interface)


for interface in vlan_interfaces:
    # get the device name from the devices list
    # we only have the device_id and have to look
    # through the devices list to find the hostname
    # since we are looking for a human readable output
    for device in devices:
        if device["id"] == interface["deviceId"]:
            device_name = device["hostname"]
            # stop the loop when we get a match!
            break

    # get the remaining two
    interface_ip_address = interface["ipv4Address"]
    interface_portname = interface["portName"]

    # format the message with data from the interface and the device name
    status = output_template.format(
        device_name=device_name,
        portname=interface_portname,
        ip_address=interface_ip_address,
    )

    # print the message
    print(status)