REST APIs
RESTful APIs (or representational state transfer APIs) use Web/HTTP services for read and modification functions. This stateless protocol has several predefined operations, as seen in Table 10-5. Because it’s a stateless protocol, the server does not maintain the state of a request. The client’s request must contain all information needed to complete a request, such as session state.
Table 10-5 REST API Operation Types
Method |
Function |
Idempotency |
Safety/Read-only Function |
---|---|---|---|
GET |
Reads resource data, settings |
YES |
YES |
HEAD |
Tests the API endpoint for validity, accessibility, and recent modifications; similar to GET without response payload |
YES |
YES |
POST |
Creates a new resource |
NO |
NO |
PUT |
Updates or replaces a resource |
YES |
NO |
PATCH |
Modifies changes to a resource (not complete replacement) |
NO |
NO |
DELETE |
Deletes a resource |
YES |
NO |
CONNECT |
Starts communications with the resource; opens a tunnel |
YES |
YES |
OPTIONS |
Provides information about the capabilities of a resource, without initiating a resource retrieval function |
YES |
YES |
API Methods
Another important aspect of a RESTful API is the API method’s idempotency, or capability to produce the same result when invoked, regardless of the number of times. The same request repeated to an idempotent endpoint should return an identical result regardless of two executions or hundreds.
API Authentication
Authentication to a RESTful API can take any number of forms: basic authentication, API key, bearer token, OAuth, or digest authentication, to name a few. Basic authentication is common, where the username is concatenated with a colon and the user’s password. The combined string is then Base64-encoded. You can easily generate the authentication string on macOS or other Linux derivatives using the built-in openssl utility. Windows platforms can achieve the same result by installing OpenSSL or obtaining a Base64-encoding utility.
Example 10-3 shows an example of generating a basic authentication string with openssl on macOS.
Example 10-3 Generating Base64 Basic Authentication String on MacOS
Mac ~ % echo -n 'myusername:DevNet4U!' | openssl base64 bXl1c2VybmFtZTpEZXZOZXQ0VSE= Mac ~ %
This method is not considered secure due to the encoding; at a minimum, the connection should be TLS-enabled so that the weak security model is at least wrapped in a layer of transport encryption.
Either API key or bearer token is more preferable from a security perspective. These models require you to generate a one-time key, usually from an administrative portal or user profile page. For example, you can enable the Meraki Dashboard API by first enabling the API for your organization: Organization > Settings > Dashboard API access. Then the associated Dashboard Administrator user can access the My Profile page to generate an API key. The key can also be revoked and a new key generated at any time, if needed.
API Pagination
API pagination serves as a method to protect API servers from overload due to large data retrieval requests. An API may limit return results, commonly rows or records, to a specific count. For example, the DNA Center REST API v2.1.2.x limits device results to 500 records at a time. To poll inventory beyond that, you would use pagination:
GET /dna/intent/api/v1/network-device/{index}/{count}
For example, if you had 1433 devices in inventory, you would use these successive polls:
GET /dna/intent/api/v1/network-device/1/500 GET /dna/intent/api/v1/network-device/501/500 GET /dna/intent/api/v1/network-device/1000/433
Other APIs may provide different cues that pagination was in effect. The API return results may include the following parameters:
Records: 2034 First: 0 Last: 999 Next: 1000
Payload Data Formats JSON XML
When dealing with REST APIs, you often need to provide a request payload containing parameters. The parameters could be anything—username to provision, interface name to poll, operating system template for a virtual machine. The API response payload body likewise has information to be consumed. In either case, it is common to work with XML- or JSON-formatted data, although others are possible and less common. These two data encoding models are conducive to programmatic use.
XML
The Extensible Markup Language (XML) is a markup language and data encoding model that has similarities to HTML. It is used to describe and share information in a programmatic but still humanly readable way.
XML documents have structure and can represent records and lists. Many people look at XML as information and data wrapped in tags. See Example 10-4 for context.
Example 10-4 XML Document
<Document> <Nodes> <Node> <Name>Router-A</Name> <Location>San Jose, CA</Location> <Interfaces> <Interface> <Name>GigabitEthernet0/0/0</Name> <IPv4Address>10.1.2.3</IPv4Address> <IPv4NetMask>255.255.255.0</IPv4NetMask> <Description>Uplink to Switch-BB</Description> </Interface> <Interface> <Name>GigabitEthernet0/0/1</Name> <IPv4Address>10.2.2.1</IPv4Address> <IPv4NetMask>255.255.255.128</IPv4NetMask> <Description /> </Interface> </Interfaces> </Node> </Nodes> </Document>
In this example, the structure of this XML document represents a router record. <Document>, <Nodes>, <Node>, <Name>, and <Location> are some of the tags created by the document author. They also define the structure. Router-A, San Jose, CA, and GigabitEthernet0/0/0 are values associated with the tags. Generally, when an XML document or schema is written, the XML tags should provide context for the value(s) supplied. The values associated with the tags are plaintext and do not convey data type. As a plaintext document, XML lends well to data exchange and compression, where needed.
XML has a history associated with document publishing. Its functional similarity with HTML provides value: XML defines and stores data, focusing on content; HTML defines format, focusing on how the content looks. The Extensible Stylesheet Language (XSL) provides a data transformation function, XSL Transformations (XSLT), for converting XML documents from one format into another, such as XML into HTML. When you consider that many APIs output results in XML, using XSLTs to convert that output into HTML is an enabling feature. This is the basis for simple “API to Dashboard” automation.
Referring to Example 10-4, you can see that XML documents contain starting tags, such as <Node>, and ending (or closing) tags, such as </Node>. There is also the convention of an empty element tag; note the <Description /> example. All elements must have an end tag or be described with the empty element tag for well-formed XML documents. Tags are case sensitive, and the start and end tags must match case. If you’re a document author, you are able to use any naming style you wish: lowercase, uppercase, underscore, Pascal case, Camel case, and so on. It is suggested that you do not use dashes (-) or periods (.) in tags to prevent misinterpretation by some processors.
All elements must be balanced in nesting, but the spacing is not prescribed. A convention of three spaces aids the reader. It is acceptable for no spacing in a highly compressed document, but the elements must still be nested among start and end tags.
XML can have attributes, similar to HTML. In the HTML example <img src="devnet_logo.png" alt="DevNet Logo" />, you can recognize attributes of src and alt with values of "devnet_logo.png" and "DevNet Logo". Similarly, in XML, data can have attributes—for example, <interface type="GigabitEthernet">0/0/0</interface>.
Attribute values, such as “GigabitEthernet”, must be surrounded by double quotes. Values between tags, such as 0/0/0, do not require quotes.
XML documents usually start with an XML declaration or prolog to describe the version and encoding being used, but it is optional:
<?xml version="1.0" encoding="UTF-8"?>
XML documents are often described as trees composed of elements. The root element starts the document. Branches and child elements define the structure with elements potentially having subelements, or children. In Example 10-4, the root element is <Document>. Because XML does not predefine tags, you may see other root element tags. Some common ones are <Root>, <DocumentRoot>, <Parent>, and <rootElement>. It is up to the document author to define the tags and structure.
The <Nodes> element is a child. The <Node> elements are also children. The <Node> elements are also siblings to each other, as a list of records. The <Name>, <IPv4Address>, <IPv4NetMask>, and <Description> elements are children to <Node>, siblings to each other and form a record. Because there are multiple <Node> elements, a list is formed.
XML documents can be viewed in browsers, typically through an Open File function. The browser may render the XML with easy-to-understand hierarchy and expand or collapse functions using + and -or ^ and > gadgets. See Figure 10-13 for another example of ACI XML data, rendered in a browser.
Figure 10.13 ACI XML Data Rendered in Browser
JSON
JavaScript Object Notation (JSON) is a newer data encoding model than XML and is growing in popularity and use with its more compact notation, ease of understanding, and closer integration with Python programming. It is lightweight, self-describing, and programming language independent. If your development includes JavaScript, then JSON is an easy choice for data encoding with its natural alignment to JavaScript syntax.
The JSON syntax provides data being written as name-value pairs. Data is separated by commas. Records or objects are defined by curly braces { }. Arrays and lists are contained within square brackets [ ].
The name of a name-value pair should be surrounded by double quotes. The value should have double quotes if representing a string. It should not have quotes if representing a numeric, Boolean (true/false), or null value. See Example 10-5 for a sample JSON record.
Example 10-5 REST API Payload as JSON
{ "Document": { "Nodes": { "Node": { "Name": "Router-A", "Location": "San Jose, CA", "InterfaceCount": 2, "Interfaces": { "Interface": [ { "Name": "GigabitEthernet0/0/0", "IPv4Address": "10.1.2.3", "IPv4NetMask": "255.255.255.0", "Description": "Uplink to Switch-BB", "isConnected": true }, { "Name": "GigabitEthernet0/0/1", "IPv4Address": "10.2.2.1", "IPv4NetMask": "255.255.255.128", "Description": null, "isConnected": false } ] } } } } }
Using this example, you can compare the structure with the previous XML representation. There is a list of interfaces; each interface is a record or object.
With APIs, the system may not give you a choice of data formatting; either XML or JSON may be the default. However, content negotiation is supported by many APIs. If the server drives the output representation, a Content-Type header shows “application/xml” or “application/json” as the response body payload type.
If the requesting client can request what’s desired, then an Accept header specifies similar values for preference. With some APIs, appending .xml or .json to the request URI returns the data with the preferred format.