6.5 Describe characteristics of REST-based APIs (CRUD, HTTP verbs, and data encoding)

I mentioned APIs earlier.  We use the APIs to communicate with software applications.  In the Cisco CCNA, we use a RESTful API or Representational State Transfer API.  What makes an API a RESTful API?

  • Client/Server Architecture.  An original application is known as a server.  A software developer creates an API as part of his application, which operates on a physical device. 

    A REST Client executes code called the REST API call.  It makes requests to the server, and the server provides information in response.

    For example, the government maintains an accurate clock API server.  If I want to know what time it is, my client sends the government API a call and the government’s server responds with the time.
  • Stateless Operation.  Each API request is independent of any other API request.  The API does not use any previous request history in deciding how to respond to a new request.  That makes it stateless.  If an API was stateful, it would maintain variables that are affected by the previous requests.
  • Statement of whether it is Cacheable or Uncacheable.  If an API is cacheable, we can reuse the data from its response.  We can cache the data and use it again in the future instead of having to make another request.

    If an API is uncacheable, then we can’t reuse the data.  We must make a new request each time we want to reuse the data.

    For example, if we were obtaining historical data, such as the price of a stock last month, we would cache it because that data doesn’t change.  If we are obtaining current data such as the price of an airline flight, we would not cache it.

    When an API provides a response, it must tell us whether we can cache it or not.  If we can cache it, the API must also provide an expiry date.
  • Uniform Interface.  That means that the all requests to the API should follow the same format, and that all responses from the API should follow the same format.  The format of the actual resource is separated from its representation.

  • Layered.  The system is layered.  When we connect to an API, we don’t know what part of the physical infrastructure we are connected to.
  • Code-on-Demand.  A server can provide the client with additional functionality by sending it executable code.

A variable is a piece of information that could change.  For example, if I was building an application to trade stocks, the current stock price would be stored inside a variable.  I might have two variables, one that lists the current stock price, and another that lists the number of shares I want to purchase.  I could multiply these variables to get the total transaction cost, and store that in a third variable.

If we’re monitoring a router, the interface’s current status could be stored in a variable.  When the interface is up, the variable’s value is “up”.  When the interface is down, the variable’s value is “down”.

When we create an application, we must give each variable a name (this is known as declaring a variable).  Depending on the type of programming language we are using, we might also need to tell the computer the type of data that it will store – text, integer number, decimal number, Boolean (true/false), etc..

A group of related variables is called an array.  For example, I could create an array for the status of the ports on my switch.  If I called the variable SwitchPortStatus, then SwitchPortStatus[1] could hold the status of Switch Port #1, SwitchPortStatus[2] could hold the status of Switch Port #2, etc..

We might call an array a list or a dictionary.  I might create an array that contains the status of a switch port.  Let’s say I want to track the following data:

  • Speed: 100
  • Duplex: auto
  • VLAN: 20

I might give the variables the names speed, duplex, and VLAN.  In a dictionary, the name of the variable is known as the key, and the value is known as the value.  We can report these variables as key:value pairs.  For example, if I ask the API to report the status of a switch port, it may reply with

[Speed:100, Duplex: auto, VLAN:20]

I can parse this data to understand the value of each variable.

Most REST APIs use HTTP, but they don’t need to.  The benefit of an HTTP API is that the HTTP protocol is understood by many devices and operating systems.  It is easy to access an HTTP API via a URL.

The HTTP API needs to allow us to do the following.  We call it CRUD.

  • Create a new variable
  • Read the contents of an existing variable
  • Update the value of an existing variable
  • Delete a variable

There are several types of HTTP messages.  Each one contains a variable which tells the server what it wants to do.  The HTTP message is contained inside a TCP/IP header.

  • HTTP POST – create a new variable
  • HTTP GET – read the contents of an existing variable
  • HTTP PUT – update a variable
  • HTTP DELETE – delete a variable

Each HTTP request also contains the name of the resource that we want to access.  For example, if we want to delete a variable, we must specify the name of the variable.

How do we know what variables are available?  How do we know what to ask the API?  The creator of the API must create a document that tells us not only the variables but also the syntax so that we can contact the API.

Our App must send an HTTP request that is directed to a specific URL.  For example

https://www.cisco.com/api/switchinterfacevalue?duplex=fullduplex might be a URL where we are informing the API that the duplex is a full duplex.  What are the different parts of the URL?

  • This URL uses the HTTPS protocol to contact the API. 
  • The hostname of the server is www.cisco.com (https://www.cisco.com)
  • The resource we’re trying to access is api/switchinterfacevalue.  This value is unique for each resource.
  • The question mark after the resource tells us that variables will follow.
  • The variable name and value.  In this case the variable name is ‘duplex, and the value we’re trying to set it to is ‘fullduplex’.  If we have multiple variables, we can separate them with an & sign.  For example ?duplex=fullduplex&speed=100&name=port1

The HTTP header can also contain authentication information.

sandboxdnac2.cisco.com is a website that we can use to experiment with Cisco DNA.  A reply from Cisco DNA will be returned in JSON format.

The software on the client needs to be able to separate the variable names and values automatically.  This is known as parsing.

A resource is a set of variables.  For example, the settings on a switch port can include the variables such as speed, duplex, VLAN, etc., and can be combined into a resource.  If we request a resource from the server, namely, the status of a switch port, the server takes the values of the variables and encodes them into a JSON format.  Our client reads the response, extracts the variables and stores them. 

JSON works well as an API response because many different programs and languages can understand JSON automatically and parse the data from its response without any additional programming.  Each language stores its variables in its own way, but many languages can convert their variables into a JSON format so that programs written in different languages can understand each other.  We can call JSON a data serialization language or a data modeling language.  We will look at some JSON examples in the last section.

The other type of language is called XML.  An XML variable is nested between tags that look like <variablename> and </variablename>.  For example, if my variable name is “duplex” and my value is “full”, I would encode the data like this

<duplex>full</duplex>

XML also lets me nest my data so that it is meaningful.  For example, I could write

<switch>

     <ports>

     <port1>

           <duplex>full</duplex>

           <speed>100</speed>

     </port1>

     <port2>

           <duplex>full</duplex>

           <speed>100</speed>

     </port2>

     </ports>

     <hostname>MainSwitch</hostname>

     <default-gateway>10.10.10.1</default-gateway>

</switch>

The outer nest is called <switch> and tells us that we have a switch configuration.  There are three nests on the second layer – <ports>, <hostname>, and <default-gateway>.  The <ports> nest lists variables for each port such as <port1> and <port2>.  Inside each of the <port1> and <port2> nests are additional variables for the speed and duplex.

We can give the variables any name we want, but it is better to give them meaningful names.  In the previous example, you can understand the XML just by looking at it.

We can indent the variables to make them easier to read, but a computer will ignore the indents.  It wouldn’t make a difference if I wrote the whole thing like this.

<switch><ports><port1><duplex>full</duplex><speed>100</speed></port1><port2><duplex>full</duplex><speed>100</speed></port2></ports><hostname>MainSwitch</hostname><default-gateway>10.10.10.1</default-gateway></switch>