<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Postman on 0x2142 | Networking Nonsense</title>
    <link>https://0x2142.com/tags/postman/</link>
    <description>Recent content in Postman on 0x2142 | Networking Nonsense</description>
    <image>
      <title>0x2142 | Networking Nonsense</title>
      <url>https://0x2142.com/logo.jpg</url>
      <link>https://0x2142.com/logo.jpg</link>
    </image>
    <generator>Hugo -- 0.143.1</generator>
    <language>en-us</language>
    <lastBuildDate>Thu, 11 Mar 2021 20:21:34 +0000</lastBuildDate>
    <atom:link href="https://0x2142.com/tags/postman/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>From Postman to Python: Your First GET Request</title>
      <link>https://0x2142.com/from-postman-to-python-your-first-get-request/</link>
      <pubDate>Thu, 11 Mar 2021 20:21:34 +0000</pubDate>
      <guid>https://0x2142.com/from-postman-to-python-your-first-get-request/</guid>
      <description>Let&amp;rsquo;s walk through a few simple Postman requests, and show how to do the same with Python</description>
      <content:encoded><![CDATA[<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
      <iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="allowfullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/nOdIyrA2l5A?autoplay=0&amp;controls=1&amp;end=0&amp;loop=0&amp;mute=0&amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"></iframe>
    </div>

<p>Maybe it&rsquo;s just me - but I feel like when we want to demonstrate product APIs to someone, we usually jump into Postman first. It&rsquo;s not without good reason though. Postman is a very easy to use platform for running API calls against REST endpoints &amp; see the nicely formatted output.</p>
<p>That being said, often times I&rsquo;ve seen that we stop there. We might mention Python as an advanced method of using our APIs, or maybe we talk about how &ldquo;if APIs are the new CLI, Postman is the new PuTTY&rdquo;. I&rsquo;ve seen some engineers who hear these statements and feel like Postman is being pushed on them - even when they&rsquo;re perfectly happy with an SSH-based CLI.</p>
<p>Network automation isn&rsquo;t usually accomplished with just one tool - it&rsquo;s a whole storage closet full of different tools &amp; utilities, each with their own use cases or specializations. In this particular example - learning Python allows you to move beyond one-off API calls in Postman, and into being able to accomplish much more complex automation.</p>
<p>So the purpose of this post is to explore how to get beyond just Postman, and into using Python for REST API calls. This isn&rsquo;t going to be a complete run-down of all the capabilities of both tools - but rather a few examples of simple GET requests using both methods.</p>
<p>If you don&rsquo;t have Postman yet, go ahead and snag the download <a href="https://www.postman.com/downloads/">here</a>.</p>
<p><em>Note: Much of the code below is minimal and does not contain any error handling. Therefore, it should not be used in a production network. Full example code <a href="https://github.com/0x2142/example-scripts/tree/master/postman-python">here</a>.</em></p>
<hr>
<h2 id="postman-simple-get-request">Postman: Simple GET Request</h2>
<p>So first, let&rsquo;s start off with an example of using Postman for a simple GET request.</p>
<p>In this example, we&rsquo;ll keep things simple &amp; use a non-authenticated API endpoint. We&rsquo;ll accomplish this using a free website called <a href="https://jsonplaceholder.typicode.com/">JSON Placeholder</a>.</p>
<p>Let&rsquo;s go ahead and start up Postman, and we&rsquo;ll see a blank workspace:</p>
<p><img alt="001&mdash;Postman-1" loading="lazy" src="/content/images/2021/03/001---Postman-1.PNG#center"></p>
<p>What we&rsquo;ll need to pay attention to first, is what type of HTTP request we&rsquo;re sending - as well as the URL we want to send our request to. If we expand the request type dropdown, we&rsquo;ll see a handful of options - but we&rsquo;ll only be using a GET request for now:</p>
<p><img alt="002&mdash;Postman" loading="lazy" src="/content/images/2021/03/002---Postman.PNG#center"></p>
<p>In order to create our first request, we&rsquo;ll just need to enter our API endpoint URL. We&rsquo;ll use the <strong>users</strong> endpoint offered by JSON Placeholder, which is located at: <a href="https://jsonplaceholder.typicode.com/users">https://jsonplaceholder.typicode.com/users</a></p>
<p><img alt="003&mdash;Postman" loading="lazy" src="/content/images/2021/03/003---Postman.png#center"></p>
<p>In the screenshot above, you&rsquo;ll see in the highlighted box that we entered our URL. Next, we just click the big <strong>Send</strong> button on the right side.</p>
<p>I already sent the GET request, so in the screenshot you&rsquo;ll also notice that we have our JSON response from the API. The mock data offered by this API provides us with a list of 10 different users, along with the data that&rsquo;s been entered for each user.</p>
<p>What if we only wanted to get data for one specific user? Well, our test API site supports using query parameters to filter our response. Let&rsquo;s say we want to find information for a user named <strong>Delphine</strong>. We would append <em>?username=Delphine</em> to our URL:</p>
<p><img alt="004&mdash;Postman" loading="lazy" src="/content/images/2021/03/004---Postman.PNG#center"></p>
<p>So as we can see above - now our JSON response only contains the data for a single user. If we needed to find a user&rsquo;s phone number, this could be an easy way to quickly filter our data &amp; get to what we need.</p>
<p>This is really where Postman is great. We&rsquo;re able to quickly &amp; visually test out an API call. We can see what the response data looks like, and understand the structure of requests &amp; responses.</p>
<p>But what about when we want to iterate through a number of users and pull only a specific few statistics? Or maybe we need a way to take a list of user information, and automatically upload or convert that data into another system.</p>
<p>For use cases like that, we&rsquo;ll jump over to Python.</p>
<h2 id="python-simple-get-request">Python: Simple GET Request</h2>
<p>In this section, we&rsquo;ll walk through the same example from above - but this time using Python.</p>
<p>First thing we&rsquo;ll need to do, is install the Python <em>requests</em> library. While there are a handful of libraries that can accomplish this work, <em>requests</em> is fairly popular &amp; easy to use.</p>
<p>So we&rsquo;ll kick things off by using pip to install our library:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">pip</span> <span class="n">install</span> <span class="n">requests</span>
</span></span></code></pre></div><p>Then, we&rsquo;ll create a very simple Python script to perform the same initial GET request from earlier. So we&rsquo;ll pull a list of ALL users from the API.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">requests</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">URL</span> <span class="o">=</span> <span class="s2">&#34;https://jsonplaceholder.typicode.com/users&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">URL</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
</span></span></code></pre></div><p>The code above should be pretty straightforward. First we&rsquo;ll import our <em>requests</em> library. Then, just to keep the code clean, we&rsquo;ll create a variable called <em>URL</em> to hold the URL for the API endpoint.</p>
<p>Next, we send that GET request, using <em>requests.get</em>. Last but not least, we&rsquo;ll go ahead and print out the text payload that we receive back. That output looks pretty similar:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">matt@DESKTOP:~/postman-python$ python3 simpleGET.py 
</span></span><span class="line"><span class="cl"><span class="o">[</span>
</span></span><span class="line"><span class="cl">  <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;id&#34;</span>: 1,
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;name&#34;</span>: <span class="s2">&#34;Leanne Graham&#34;</span>,
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;username&#34;</span>: <span class="s2">&#34;Bret&#34;</span>,
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;email&#34;</span>: <span class="s2">&#34;Sincere@april.biz&#34;</span>,
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;address&#34;</span>: <span class="o">{</span>
</span></span><span class="line"><span class="cl">      <span class="s2">&#34;street&#34;</span>: <span class="s2">&#34;Kulas Light&#34;</span>,
</span></span><span class="line"><span class="cl">      <span class="s2">&#34;suite&#34;</span>: <span class="s2">&#34;Apt. 556&#34;</span>,
</span></span><span class="line"><span class="cl">      <span class="s2">&#34;city&#34;</span>: <span class="s2">&#34;Gwenborough&#34;</span>,
</span></span><span class="line"><span class="cl">      <span class="s2">&#34;zipcode&#34;</span>: <span class="s2">&#34;92998-3874&#34;</span>,
</span></span><span class="line"><span class="cl">      <span class="s2">&#34;geo&#34;</span>: <span class="o">{</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;lat&#34;</span>: <span class="s2">&#34;-37.3159&#34;</span>,
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;lng&#34;</span>: <span class="s2">&#34;81.1496&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="o">}</span>
</span></span><span class="line"><span class="cl">    <span class="o">}</span>,
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;phone&#34;</span>: <span class="s2">&#34;1-770-736-8031 x56442&#34;</span>,
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;website&#34;</span>: <span class="s2">&#34;hildegard.org&#34;</span>,
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;company&#34;</span>: <span class="o">{</span>
</span></span><span class="line"><span class="cl">     -- output truncated --
</span></span></code></pre></div><p>Now, let&rsquo;s add a little extra logic to our next step. Rather than just specifying a static username that we want to search for, let&rsquo;s ask our user to specify a username:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">requests</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">URL</span> <span class="o">=</span> <span class="s2">&#34;https://jsonplaceholder.typicode.com/users&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Search by Username:&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">user</span> <span class="o">=</span> <span class="nb">input</span><span class="p">(</span><span class="s2">&#34;&gt; &#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">queryURL</span> <span class="o">=</span> <span class="n">URL</span> <span class="o">+</span> <span class="sa">f</span><span class="s2">&#34;?username=</span><span class="si">{</span><span class="n">user</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">queryURL</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
</span></span></code></pre></div><p>In the code above, we made just a few changes. One is printing out a prompt to &ldquo;Search by Username&rdquo;. Then we use the Python <em>input</em> function to collect input from our user, then store that in the <em>user</em> variable.</p>
<p>Next, we create a <em>queryURL</em> - which is similar to the URL we used in the Postman example. Except in this case, we&rsquo;re supplying a dynamic username input based on whatever the end user wants to search for. We use a Python <a href="https://realpython.com/python-f-strings/">f-string</a> to inject the username into our query parameters.</p>
<p>Let&rsquo;s see what that looks like:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">matt@DESKTOP:~/postman-python$ python3 simpleGET.py 
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Search by Username:
</span></span><span class="line"><span class="cl">&gt; Delphine
</span></span><span class="line"><span class="cl"><span class="o">[</span>
</span></span><span class="line"><span class="cl">  <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;id&#34;</span>: 9,
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;name&#34;</span>: <span class="s2">&#34;Glenna Reichert&#34;</span>,
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;username&#34;</span>: <span class="s2">&#34;Delphine&#34;</span>,
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;email&#34;</span>: <span class="s2">&#34;Chaim_McDermott@dana.io&#34;</span>,
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;address&#34;</span>: <span class="o">{</span>
</span></span><span class="line"><span class="cl">      <span class="s2">&#34;street&#34;</span>: <span class="s2">&#34;Dayna Park&#34;</span>,
</span></span><span class="line"><span class="cl">      <span class="s2">&#34;suite&#34;</span>: <span class="s2">&#34;Suite 449&#34;</span>,
</span></span><span class="line"><span class="cl">      <span class="s2">&#34;city&#34;</span>: <span class="s2">&#34;Bartholomebury&#34;</span>,
</span></span><span class="line"><span class="cl">      <span class="s2">&#34;zipcode&#34;</span>: <span class="s2">&#34;76495-3109&#34;</span>,
</span></span><span class="line"><span class="cl">      <span class="s2">&#34;geo&#34;</span>: <span class="o">{</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;lat&#34;</span>: <span class="s2">&#34;24.6463&#34;</span>,
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;lng&#34;</span>: <span class="s2">&#34;-168.8889&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="o">}</span>
</span></span><span class="line"><span class="cl">    <span class="o">}</span>,
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;phone&#34;</span>: <span class="s2">&#34;(775)976-6794 x41206&#34;</span>,
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;website&#34;</span>: <span class="s2">&#34;conrad.com&#34;</span>,
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;company&#34;</span>: <span class="o">{</span>
</span></span><span class="line"><span class="cl">      <span class="s2">&#34;name&#34;</span>: <span class="s2">&#34;Yost and Sons&#34;</span>,
</span></span><span class="line"><span class="cl">      <span class="s2">&#34;catchPhrase&#34;</span>: <span class="s2">&#34;Switchable contextually-based project&#34;</span>,
</span></span><span class="line"><span class="cl">      <span class="s2">&#34;bs&#34;</span>: <span class="s2">&#34;aggregate real-time technologies&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="o">}</span>
</span></span><span class="line"><span class="cl">  <span class="o">}</span>
</span></span><span class="line"><span class="cl"><span class="o">]</span>
</span></span></code></pre></div><p>Perfect! We get the result we expected, which is the single dataset from the user that we specified.</p>
<p>Let&rsquo;s take this one step further! Maybe we want to build a quick utility to search for a user&rsquo;s contact information. We can take the raw JSON output, pull out a few pieces of info, then apply some formatting to make it more user-friendly.</p>
<p>In the following example, we&rsquo;ll update our code to search that JSON response &amp; collect the user&rsquo;s name, email address, and phone number.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">requests</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">json</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">URL</span> <span class="o">=</span> <span class="s2">&#34;https://jsonplaceholder.typicode.com/users&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Search by Username:&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">user</span> <span class="o">=</span> <span class="nb">input</span><span class="p">(</span><span class="s2">&#34;&gt; &#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">queryURL</span> <span class="o">=</span> <span class="n">URL</span> <span class="o">+</span> <span class="sa">f</span><span class="s2">&#34;?username=</span><span class="si">{</span><span class="n">user</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">response</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">queryURL</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">userdata</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">text</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">name</span> <span class="o">=</span> <span class="n">userdata</span><span class="p">[</span><span class="s2">&#34;name&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">email</span> <span class="o">=</span> <span class="n">userdata</span><span class="p">[</span><span class="s2">&#34;email&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">phone</span> <span class="o">=</span> <span class="n">userdata</span><span class="p">[</span><span class="s2">&#34;phone&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2"> can be reached via the following methods:&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Email: </span><span class="si">{</span><span class="n">email</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;Phone: </span><span class="si">{</span><span class="n">phone</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span></code></pre></div><p>So a few things have changed in the above example. First thing you may notice, is that we&rsquo;ve added an additional import: the <strong>json</strong> library. We use this in line 11, where we convert the JSON output into a native python object using the <em>json.loads</em> function.</p>
<p>What this allows us to do is easily pull individual data values from the JSON output. In the original JSON data that we received, we saw a bunch of user data organized into key-value pairs. So once we load that JSON into a Python dictionary, we can pull out individual values and assign them to variables.</p>
<p>Finally - we can print all of that data out to our terminal:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">matt@DESKTOP:~/postman-python$ python3 simpleGET.py
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Search by Username:
</span></span><span class="line"><span class="cl">&gt; Delphine
</span></span><span class="line"><span class="cl">Glenna Reichert can be reached via the following methods:
</span></span><span class="line"><span class="cl">Email: Chaim_McDermott@dana.io
</span></span><span class="line"><span class="cl">Phone: <span class="o">(</span>775<span class="o">)</span>976-6794 x41206
</span></span></code></pre></div><p>Nothing super fancy here - but this could be the beginnings of building out a user search web page, or maybe importing certain data fields into another system. Once we get the basics of working with REST APIs out of the way, there are a ton of possibilities for what can be built.</p>
<h2 id="okay---what-about-network-automation">Okay - What About Network Automation?</h2>
<p>Many new network technologies are now API enabled. Nearly every cloud-hosted platform or management controller offers some method of interacting programmatically. In fact, most routers &amp; switches even offer a REST-based API that can be used for automated configuration or monitoring.</p>
<p>So let&rsquo;s take the following example: We have a couple of Meraki networks, and we&rsquo;ve been tasked with providing a report of how many total clients have connected to our network in the last 30 days. In addition, it would be nice to see a breakdown of the distribution of operating systems.</p>
<p>Let&rsquo;s take a look at the following screenshot from Postman:</p>
<p><img alt="005&mdash;Postman" loading="lazy" src="/content/images/2021/03/005---Postman.png#center"></p>
<p>Using Meraki&rsquo;s <a href="https://developer.cisco.com/meraki/api-v1/#!get-network-clients">API docs</a>, we can determine the exact URL endpoint we need to query. This URL requires that we know the exact network ID for the network we want to get info from, which we&rsquo;ll pretend we already know. Also not shown here, we have an additional HTTP header that includes our API key - which was generated in Meraki Dashboard.</p>
<p>In addition, we have a few query parameters to help make sure we get the data we need. By default, this API endpoint will return 10 devices. In this particular network, we already know we have more than 10 - so we use the <em>perPage</em> query parameter to request up to 100 devices. We also wanted to query the last 30 days of devices, so we use the <em>timespan</em> parameter. This parameter expects the lookback to be in seconds, so we specify 43,200 seconds.</p>
<p>So we got back a list of devices - and specifically in the example shown, it looks like we have an Android device on our network. Easy enough to spot that info, right?</p>
<p>Well - maybe we have more than a handful of devices. We don&rsquo;t want to manually sort through all of that data &amp; assemble a list. Or maybe this task needs to be run more than once. This is where we can use Python to automatically assemble that report with just a few lines of code.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">requests</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">json</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">URL</span> <span class="o">=</span> <span class="s2">&#34;https://api.meraki.com/api/v1&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">APIKEY</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&#34;X-Cisco-Meraki-API-Key&#34;</span><span class="p">:</span> <span class="s2">&#34;xxxxxxxxxxxxxxxxx&#34;</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="o">---</span> <span class="n">Code</span> <span class="n">omitted</span> <span class="o">---</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">getClients</span><span class="p">(</span><span class="n">orgID</span><span class="p">,</span> <span class="n">networkList</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="s2">    Query clients for each network, return client list
</span></span></span><span class="line"><span class="cl"><span class="s2">    &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">clientCount</span> <span class="o">=</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">    <span class="n">total</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># Query Parameters: Return up to 100 devices seen in the past 43,200 seconds (30 days)</span>
</span></span><span class="line"><span class="cl">    <span class="n">q</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&#34;perPage&#34;</span><span class="p">:</span> <span class="s2">&#34;100&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">         <span class="s2">&#34;timespan&#34;</span><span class="p">:</span> <span class="s2">&#34;43200&#34;</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">network</span> <span class="ow">in</span> <span class="n">networkList</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># Query clients for each network</span>
</span></span><span class="line"><span class="cl">        <span class="n">queryURL</span> <span class="o">=</span> <span class="n">URL</span> <span class="o">+</span> <span class="sa">f</span><span class="s2">&#34;/networks/</span><span class="si">{</span><span class="n">network</span><span class="si">}</span><span class="s2">/clients&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="n">response</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">queryURL</span><span class="p">,</span> <span class="n">params</span><span class="o">=</span><span class="n">q</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="n">APIKEY</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">data</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># Grab client OS from each device &amp; append to clientCount dictionary</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">client</span> <span class="ow">in</span> <span class="n">data</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="n">clientCount</span><span class="p">[</span><span class="n">client</span><span class="p">[</span><span class="s2">&#34;os&#34;</span><span class="p">]]</span> <span class="o">+=</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl">            <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="n">clientCount</span><span class="p">[</span><span class="n">client</span><span class="p">[</span><span class="s2">&#34;os&#34;</span><span class="p">]]</span> <span class="o">=</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl">            <span class="k">except</span> <span class="ne">TypeError</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="k">continue</span>
</span></span><span class="line"><span class="cl">            <span class="n">total</span> <span class="o">+=</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># Append final count of all devices &amp; return dict</span>
</span></span><span class="line"><span class="cl">    <span class="n">clientCount</span><span class="p">[</span><span class="s2">&#34;Total Devices&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="n">total</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">clientCount</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">printReport</span><span class="p">(</span><span class="n">clientOS</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="s2">    Print final output to terminal
</span></span></span><span class="line"><span class="cl"><span class="s2">    &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Count of clients by operating system:&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">OS</span> <span class="ow">in</span> <span class="n">clientOS</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">OS</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">clientOS</span><span class="p">[</span><span class="n">OS</span><span class="p">]</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl"><span class="o">---</span> <span class="n">Code</span> <span class="n">omitted</span> <span class="o">---</span>
</span></span></code></pre></div><p>To keep things simple - we&rsquo;ll only look at a snippet of the code. The entire example will be posted to <a href="https://github.com/0x2142/example-scripts/tree/master/postman-python">GitHub</a>, and contains two additional functions that will automatically find our Organization ID &amp; Network ID.</p>
<p>In our <em>getClients</em> function, we create an empty Python dictionary to hold our list of client operating systems - and we also create a <em>total</em> variable which we&rsquo;ll increment for every client in the list.</p>
<p>The HTTP GET request should look fairly similar to what we used previously. The big difference is that we&rsquo;re creating a dictionary called <em>q</em> to hold our <em>perPage</em> &amp; <em>timespan</em> query parameters. Then we include that in our GET request by adding <em>params=q</em> to the request.</p>
<p>Next - we convert the JSON response into a Python object, and walk through every device in that list. For each device in the list, we look at the &ldquo;os&rdquo; value to determine the operating system detected by Meraki. We then use a try/except block to see if we can increment the counter for that operating system. If we get a <strong>KeyError</strong>, then we know the OS isn&rsquo;t currently on the list &amp; we can just add it with a new value of 1.</p>
<p>After all that has been completed, we return our <em>clientCount</em> dictionary - which our primary function passes to the <em>printReport</em> function. This just prints out a header, then iterates through our <em>clientCount</em> dictionary and prints each operating system &amp; count.</p>
<p>Let&rsquo;s take a look at that output below:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">matt@DESKTOP:~/postman-python$ python getOScount.py
</span></span><span class="line"><span class="cl">Count of clients by operating system:
</span></span><span class="line"><span class="cl">None: <span class="m">9</span>
</span></span><span class="line"><span class="cl">Sailfish OS: <span class="m">2</span>
</span></span><span class="line"><span class="cl">Nokia: <span class="m">1</span>
</span></span><span class="line"><span class="cl">Windows 10: <span class="m">2</span>
</span></span><span class="line"><span class="cl">Raspberry Pi: <span class="m">2</span>
</span></span><span class="line"><span class="cl">Android: <span class="m">4</span>
</span></span><span class="line"><span class="cl">Meraki OS: <span class="m">1</span>
</span></span><span class="line"><span class="cl">Total Devices: <span class="m">21</span>
</span></span></code></pre></div><p>In the list above, we can see that we have a total of 21 devices in our network - and 7 different operating systems were found as well.</p>
<p>That output may not be the prettiest of reports, but it was accomplished with ~50 lines of Python &amp; takes less than a few seconds to run. If we wanted to format the data in another way, or include data from a non-Meraki source, we absolutely could.</p>
<p>That&rsquo;s part of what&rsquo;s exciting about using Python for network automation - most anything we could think of doing is possible.</p>
<h2 id="tip-use-postman-to-generate-python-code">TIP: Use Postman to Generate Python Code</h2>
<p>Okay - so I wanted to save this bit for last. Now that you&rsquo;ve seen examples in both tools, I wanted to make sure we cover a feature in postman that can save some time.</p>
<p>So over in the right-hand side of your Postman window, you&rsquo;ll see an icon that looks like this: <strong>&lt;/&gt;</strong></p>
<p><img alt="006&mdash;Postman" loading="lazy" src="/content/images/2021/03/006---Postman.png#center"></p>
<p>If you click that, you&rsquo;ll see a dropdown menu of various languages &amp; tools. Select one of those options and Postman will auto-generate code you can use. This auto-generated code will execute the same request you have built in the Postman GUI.</p>
<p>For example, our last Postman request we used to get Meraki clients:</p>
<p><img alt="007&mdash;Postman" loading="lazy" src="/content/images/2021/03/007---Postman.png#center"></p>
<p>I wanted to save this for last, because I feel like it&rsquo;s important to understand how to write the code manually first - then take advantages of shortcuts after having a good understanding of what the code is doing.</p>
<hr>
<p>That&rsquo;s about all I had for this example. Again, my intent here wasn&rsquo;t to create an all-inclusive resource for how to use Postman &amp; Python - but rather to give some examples for each one &amp; show where/why each would be used.</p>
<p>I&rsquo;ve met a handful of people over the years who have seen many API demos using Postman, but aren&rsquo;t sold yet on the value of learning Python &amp; getting into network automation.</p>
<p>Hopefully these examples help bridge that gap a little bit 😄</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
