Cisco Meraki REST API calls with Python’s requests library

In the previous articles, I’ve described how to execute REST API calls using Postman software. This time we will dive into Python.

Tools

To run REST API calls we will use Python3 with the requests library. It’s not installed by default, so make sure it’s present before jumping further.

Environment

We will use the Cisco Meraki Always on sandbox. It’s a free lab environment that everybody can access to test various Meraki functionalities.

The base URL for API calls will be https://api.meraki.com/api/v0

For authentication we will use a API key, at the time of this article writing, API key is: 6bec40cf957de430a6f1f2baa056b99a4fac9ea0

You can find Cisco Meraki API documentation here.

API Calls

The following chapters are containing python source code. If you’re interested in running those scripts on your local machine, you can easily access them on the GitLab repository.

Organizations

We will start with script that gathers information about all organizations.

import requests
import json

BASE_URL = 'https://api.meraki.com/api/v0'
headers = { 'X-Cisco-Meraki-API-Key': '6bec40cf957de430a6f1f2baa056b99a4fac9ea0' }
RESOURCE = '/organizations'

call_response = requests.get(BASE_URL + RESOURCE, headers=headers)
parsed_response = json.loads(call_response.text)

for organization in parsed_response:
    print('ID: {id}, Name: {name}'.format(id=organization['id'], name=organization['name']))

First of all, we’re importing the necessary libraries. Requests will be used for REST API calls. The API call returns a JSON string, so the JSON library will be used for conversion to the python data structures.

BASE_URL variable contains a URL to the Cisco Meraki environment. Our API call URL’s will be created by appending the appropriate string.

We will use the API key for authorization. In the headers dictionary, there is one key/value pair with authorization details.

RESOURCE variable determines the resource that we want to access with the REST API call. You can find a complete list of available options in the official documentation.

Since we have all necessary information, let’s execute our first REST API call!

We want to execute a GET request, that’s why we’re using a get method from the requests library. The first argument is the combination of the basic URL with a specified resource, that we want to access. The resulting string is as follows.

https://api.meraki.com/api/v0/organizations

A second argument is a dictionary with authorization details. We’re passing it explicitly as a header.

Let’s pause here for a second before jumping to the following line codes.

After execution of the REST API call, we’re receiving following object.

The requests.Response object was returned by the GET method. As we can see, there is a response code 200, which determines, that the call was successful. The call_response variable now has plenty of properties, but we will focus on the text, which returns the REST API response in the Unicode text.

Since the response is encoded in the JSON format, it’s convenient to convert it to the native python structures. It can be easily accomplished using the JSON library. The loads method takes the JSON string and converts it to the python data structures. After decoding, the parse_response variable is a list with dictionary elements.

From now on, the data can be easily accessed via native python utilities. Let’s loop through all organizations first. The single organization is built of a dictionary with keys of id, name, and url.

Let’s say that we want to print just id and name of the organization. Since it’s a dictionary, we can access the data with the standard Python syntax.

The output from the script is as follows.

ID: 681155, Name: DeLab
ID: 566327653141842188, Name: DevNetAssoc
ID: 575334852396582607, Name: 123456
ID: 575334852396582606, Name: TriDeptrai
ID: 575334852396582605, Name: My organization
ID: 575334852396582604, Name: thanh
ID: 575334852396582603, Name: 123456
ID: 575334852396582602, Name: My organization
ID: 575334852396582601, Name: 123
ID: 575334852396582600, Name:vnPro
ID: 575334852396582591, Name: Ftreqah organization
ID: 575334852396582590, Name: Ftreqah organization
ID: 575334852396582587, Name:vnPro
ID: 549236, Name: DevNet Sandbox
ID: 52636, Name: Forest City - Other
ID: 865776, Name: Cisco Live US 2019
ID: 463308, Name: DevNet San Jose

Networks

Now let’s jump to networks. In Meraki, an organization can have assigned one or more networks. Let’s say that we want to print all organizations and networks.

import requests
import json

BASE_URL = 'https://api.meraki.com/api/v0'
headers = { 'X-Cisco-Meraki-API-Key': '6bec40cf957de430a6f1f2baa056b99a4fac9ea0' }
RESOURCE = '/organizations'

call_response = requests.get(BASE_URL + RESOURCE, headers=headers)
organizations = json.loads(call_response.text)

for organization in organizations:
    RESOURCE = '/organizations/{id}/networks'.format(id=organization['id'])
    call_response = requests.get(BASE_URL + RESOURCE, headers=headers)
    networks = json.loads(call_response.text)

    if len(networks) > 0:
        print('Printing networks for organization {name}:'.format(name=organization['name']))

        for network in networks:
            print('\tID: {id}, Name: {name}, Type: {type}'.format(id=network['id'],
                                                                  name=network['name'],
                                                                  type=network['type']))
    else:
        print('There are no networks assigned to organization {name}'.format(name=organization['name']))

First of all, we have to grab a list of organizations. After that, we have to loop through each organization(first for loop) and grab an organization id. Now we can build an API call gathering all networks assigned to a specified organization.

Down below you can find a syntax of the REST API call, that returns a list of networks assigned to a particular organization.

https://api.meraki.com/api/v0/organizations/{organization_id}/networks

If a particular organization has assigned networks, we’re looping through them and printing information in the second for loop. On the screenshot below you can find attributes of each network.

In this case, we want to print a network id, name, and type. In the following snippet, you can find the result.

Printing networks for organization DeLab:
	ID: L_566327653141843049, Name: Lyoli, Type: combined
	ID: L_566327653141846927, Name: Vegas Apartment, Type: combined
	ID: N_566327653141899127, Name: Nolan, Type: wireless
	ID: N_566327653141902646, Name: Lyoli MDM, Type: systems manager
	ID: L_566327653141856846, Name: DevNetLab, Type: combined
	ID: L_566327653141856854, Name: DNEAlertsNet, Type: combined
Printing networks for organization DevNetAssoc:
	ID: L_566327653141858539, Name: DevNetAssoc1, Type: combined
	ID: L_566327653141858540, Name: DevNetAssoc2, Type: combined
	ID: L_566327653141858541, Name: DevNetAssoc3, Type: combined
	ID: L_566327653141858542, Name: DevNetAssoc4, Type: combined
	ID: L_566327653141858543, Name: DevNetAssoc5, Type: combined
There are no networks assigned to organization 123456
There are no networks assigned to organization TriDeptrai
There are no networks assigned to organization My organization
There are no networks assigned to organization thanh
There are no networks assigned to organization 123456
There are no networks assigned to organization My organization
There are no networks assigned to organization 123
There are no networks assigned to organizationvnPro
Printing networks for organization Ftreqah organization:
	ID: L_575334852396596103, Name: Long Island Ftreqah Office, Type: combined
There are no networks assigned to organization Ftreqah organization
There are no networks assigned to organizationvnPro
Printing networks for organization DevNet Sandbox:
	ID: L_646829496481105433, Name: DevNet Sandbox ALWAYS ON, Type: combined
	ID: L_646829496481106542, Name: DNSMB3-exxxxateletex.com.br, Type: combined
	ID: L_646829496481106617, Name: DNSMB4-oxxxxx8gmail.com, Type: combined
	ID: L_646829496481106633, Name: DNENT1-Cxxxxemaac.com, Type: combined
	ID: L_646829496481106654, Name: DNSMB5-nxxxxxxxnelasalle.com, Type: combined
	ID: L_646829496481106658, Name: DNENT3, Type: combined
	ID: L_646829496481106677, Name: DNENT2-sxxxxnzohocorp.com, Type: combined
	ID: L_646829496481106683, Name: DNSMB2-gxxxacisco.com, Type: combined
Printing networks for organization Forest City - Other:
	ID: N_586593851465008648, Name: 2nd floor - Terminal Tower, Type: wireless
Printing networks for organization Cisco Live US 2019:
	ID: N_575334852396609596, Name: My network, Type: wireless
Printing networks for organization DevNet San Jose:
	ID: L_573083052582899526, Name: Cisco Live Network, Type: combined
	ID: L_573083052582908089, Name: San Jose Lab, Type: combined
	ID: N_573083052582971004, Name: EMM Test, Type: systems manager
	ID: N_573083052583209321, Name: OTG Test Network, Type: appliance
	ID: L_573083052582981640, Name: OTG Test Network, Type: combined

Devices

The last example is pretty similar to the previous one. In this case, we’re listing devices, that are assigned to each network.

import requests
import json

BASE_URL = 'https://api.meraki.com/api/v0'
headers = {'X-Cisco-Meraki-API-Key': '6bec40cf957de430a6f1f2baa056b99a4fac9ea0'}
RESOURCE = '/organizations'

call_response = requests.get(BASE_URL + RESOURCE, headers=headers)
organizations = json.loads(call_response.text)

for organization in organizations:
    RESOURCE = '/organizations/{id}/networks'.format(id=organization['id'])
    call_response = requests.get(BASE_URL + RESOURCE, headers=headers)
    networks = json.loads(call_response.text)

    for network in networks:
        RESOURCE = '/networks/{id}/devices'.format(id=network['id'])
        call_response = requests.get(BASE_URL + RESOURCE, headers=headers)
        devices = json.loads(call_response.text)

        if len(devices) > 0:
            print('Devices assigned to network {network}'.format(network=network['name']))

            for device in devices:
                if 'name' in device:
                    print('\tName: {name}, Model: {model}, Serial: {serial}'.format(name=device['name'],
                                                                                    model=device['model'],
                                                                                    serial=device['serial']))
                else:
                    print('\tModel: {model}, Serial: {serial}'.format(model=device['model'],
                                                                      serial=device['serial']))
        else:
            print('There are no devices assigned to the network {network}'.format(network=network['name']))

To list devices assigned to a particular network, we need to gather all networks. We’re doing it the same way as in the previous example. After we have a network id’s, we’re ready to list devices for each network. The API call to accomplish this is the following.

https://api.meraki.com/api/v0/networks/{network_id}/devices

After the API call execution, we have a list of devices. The attributes of each device are as follows.

Since we have all the necessary information, we can print the information. We’re grabbing the name, model, and serial of each network device. The result of the script is down below.

Devices assigned to network Lyoli
	Name: BigCat, Model: MX250, Serial: Q2SW-SWQ2-HZ9L
	Name: 1st Floor AP, Model: MR52, Serial: Q2LD-GYL3-KEHX
	Name: 2nd Floor AP, Model: MR52, Serial: Q2LD-AN9B-S6AJ
	Name: Sun Room, Model: MR84, Serial: Q2EK-UKGM-XSD9
	Name: Office AP, Model: MR52, Serial: Q2LD-ZWCZ-UA77
	Name: Basement AP, Model: MR52, Serial: Q2LD-3Y7V-7Y2X
	Model: MV12W, Serial: Q2GV-LDX2-53ZA
	Name: Big Office Switch, Model: MS250-48FP, Serial: Q2QW-W2W4-MCNR
	Name: Bedroom Switch, Model: MS220-8P, Serial: Q2HP-WEUW-2PQD
	Name: Basement switch, Model: MS220-8P, Serial: Q2HP-225A-XA5C
Devices assigned to network Vegas Apartment
	Model: MV71, Serial: Q2CV-V49B-RCMZ
	Name: Alex’s MR32, Model: MR32, Serial: Q2JD-7RNY-EB7Z
	Name: Alex's MR84 - 1, Model: MR84, Serial: Q2EK-2LYB-PCZP
	Name: Vegas Balcony MR84, Model: MR84, Serial: Q2EK-D4XP-235S
	Model: MR84, Serial: Q2EK-ACGE-URXL
	Name: Vegas Living Room MR84, Model: MR84, Serial: Q2EK-3UBE-RRUY
	Model: MX65, Serial: Q2QN-Y5ED-P57W
Devices assigned to network Nolan
	Model: MR52, Serial: Q2LD-X2S2-AG2U
	Model: MR52, Serial: Q2LD-N2U5-D83H
There are no devices assigned to the network Lyoli MDM
[...]

Summary

As you can probably deduce, REST API calls are a powerful tool in the network engineer hands. They can be used in a variety of different ways. Do you have a network device stocktaking? You can easily gather all the necessary information and save it in a convenient way. It’s just one use case that can save you a lot of work and time.

Share

2 thoughts on “Cisco Meraki REST API calls with Python’s requests library

  1. Hi, I was excited to try out this script which is exactly what I needed but when I tried it seems its is going on loop. I am not sure what is the cause though. Any ideas? Thank you.

Leave a Reply

Your email address will not be published. Required fields are marked *