Cisco IP SLA IOS-XE

Cisco IP Service Level Agreements (SLAs) is a proprietary feature available on Cisco routers and switches, which actively generates monitoring traffic, processes replies, and measures network performance.

This feature can be used to perform continuous end-to-end connectivity testing with automated re-routing over failover links. It can also simulate different application behavior, such as voice and video to check if the network provides the expected level of service.

The examples and features described in this article are based on Cisco IOS-XE version 16.9.

Configuration Components

IP SLA configuration starts with defining an SLA operation and then scheduling it to run immediately or at a specific time.

SLA Operation Definition

To create or edit an SLA operation use the “ip sla <operation-id>” global configuration mode command. It places CLI into the IP SLA configuration sub-mode, where you can select one of the IP SLA types and provide corresponding configuration parameters.

One of the simplest types of IP SLA operations is icmp-echo. The router pings a specified IP address and records round-trip times if the remote side is reachable. In the example below, we will set the type of SLA entry as ICMP echo with the destination’s IP address of 10.0.3.1. The sample topology is shown in Figure 1.

Figure 1. IP SLA Test Topology
Figure 1. IP SLA Test Topology

The configuration mode changes to IP SLA echo where you can adjust different optional parameters, such as request sending frequency and timeout for replies.

X(config)#ip sla 1 
X(config-ip-sla)# icmp-echo 10.0.3.1 source-ip 10.0.0.1
X(config-ip-sla-echo)#?
IP SLAs Icmp Echo Configuration Commands:
  data-pattern       Data Pattern
  default            Set a command to its defaults
  exit               Exit operation configuration
  frequency          Frequency of an operation
  history            History and Distribution Data
  no                 Negate a command or set its defaults
  owner              Owner of Entry
  request-data-size  Request data size
  tag                User defined tag
  threshold          Operation threshold in milliseconds
  timeout            Timeout of an operation
  tos                Type Of Service
  verify-data        Verify data
  vrf                Configure IP SLAs for a VRF

Scheduling IP SLA

Once SLA is defined and optional parameters are specified, start it by running the “ip sla schedule <id>” command. IP SLA can be configured to start at a specific time or as soon as the command is entered, which is shown in the example below.

X(config)#ip sla schedule 1 start-time now life forever

To check SLA operation’s details use the “show ip sla statistics <id> details” command.

X#show ip sla statistics 1 details 
IPSLAs Latest Operation Statistics

IPSLA operation id: 1
        Latest RTT: 1 milliseconds
Latest operation start time: 10:08:18 UTC Sat Jan 30 2021
Latest operation return code: OK
Over thresholds occurred: FALSE
Number of successes: 2
Number of failures: 0
Operation time to live: Forever
Operational state of entry: Active
Last time this entry was reset: Never

To see configuration details, including default values for various parameters, use the “show ip sla configuration” command.

X#show ip sla configuration  
IP SLAs Infrastructure Engine-III
Entry number: 1
Owner: 
Tag: 
Operation timeout (milliseconds): 5000
Type of operation to perform: icmp-echo
Target address/Source address: 10.0.3.1/10.0.0.1
Type Of Service parameter: 0x0
Request size (ARR data portion): 28
Data pattern: 0xABCDABCD
Verify data: No
Vrf Name: 
Schedule:
   Operation frequency (seconds): 60  (not considered if randomly scheduled)
   Next Scheduled Start Time: Start Time already passed
   Group Scheduled : FALSE
   Randomly Scheduled : FALSE
   Life (seconds): Forever
   Entry Ageout (seconds): never
   Recurring (Starting Everyday): FALSE
   Status of entry (SNMP RowStatus): Active
Threshold (milliseconds): 5000
Distribution Statistics:
   Number of statistic hours kept: 2
   Number of statistic distribution buckets kept: 1
   Statistic distribution interval (milliseconds): 20
Enhanced History:
History Statistics:
   Number of history Lives kept: 0
   Number of history Buckets kept: 15
   History Filter Type: None

Once SLA operation is scheduled, it cannot be modified. Instead, the old operation can be deleted, and then a new one created again using the same ID.

Different IP SLA Types

To view available types of SLA operations, use context-sensitive help as shown in the next example.

X(config-ip-sla)#?
IP SLAs entry configuration commands:
  dhcp         DHCP Operation
  dns          DNS Query Operation
  ethernet     Ethernet Operations
  exit         Exit Operation Configuration
  ftp          FTP Operation
  http         HTTP Operation
  icmp-echo    ICMP Echo Operation
  icmp-jitter  ICMP Jitter Operation
  mpls         MPLS Operation
  path-echo    Path Discovered ICMP Echo Operation
  path-jitter  Path Discovered ICMP Jitter Operation
  tcp-connect  TCP Connect Operation
  udp-echo     UDP Echo Operation
  udp-jitter   UDP Jitter Operation

The next subsections will review some of them.

Jitter operations

Jitter is a variation in the delay between packets. The smaller the jitter the better performance of time-sensitive applications such as voice. It also means that the network delivers packets with a predictable delay and doesn’t experience congestions causing intermittent delays along the paths.

There are 2 types of SLA operations performing Jitter measurements – ICMP and UDP-based.

ICMP Jitter

ICMP Jitter SLA operation is based on ICMP message types (Timestamp Request and Timestamp Reply). The destination can be any device that supports these ICMP messages. Not all devices support it, or it can be blocked by the firewalls. The previously shown ICMP Echo operation is based on more commonly used Echo and Reply message types.

The configuration in the example below demonstrates how to configure ICMP jitter operation and, that once launched, it reports the round-trip-time (RTT) and jitter statistics from the source to the destination, and vice versa.

X(config)# ip sla 2 
X(config-ip-sla)# icmp-jitter 10.0.3.1 source-ip 10.0.0.1
X(config)# ip sla schedule 2 start-time now life forever

X#show ip sla statistics 2
IPSLAs Latest Operation Statistics

IPSLA operation id: 2
Type of operation: icmp-jitter
        Latest RTT: 1 milliseconds
Latest operation start time: 00:20:39 UTC Sun Jan 31 2021
Latest operation return code: OK
RTT Values:
        Number Of RTT: 10               RTT Min/Avg/Max: 1/1/1 milliseconds
Latency one-way time:
        Number of Latency one-way Samples: 0
        Source to Destination Latency one way Min/Avg/Max: 0/0/0 milliseconds
        Destination to Source Latency one way Min/Avg/Max: 0/0/0 milliseconds
Jitter Time:
        Number of SD Jitter Samples: 9
        Number of DS Jitter Samples: 9
        Source to Destination Jitter Min/Avg/Max: 0/1/1 milliseconds
        Destination to Source Jitter Min/Avg/Max: 0/1/1 milliseconds
Over Threshold:
        Number Of RTT Over Threshold: 0 (0%)
Packet Late Arrival: 0
Out Of Sequence: 0
        Source to Destination: 0        Destination to Source 0
        In both Directions: 0
Packet Skipped: 0       Packet Unprocessed: 0
Packet Loss: 0
        Loss Periods Number: 0
        Loss Period Length Min/Max: 0/0
        Inter Loss Period Length Min/Max: 0/0
Number of successes: 4
Number of failures: 0
Operation time to live: Forever

To measure jitter, a source router sends a number of packets (10, by default) periodically. The time between these packets is called interval (20ms). The operation is repeated at a specified frequency (60 seconds by default).

The example below shows default configuration values – every 60 seconds the router will send 10 packets with 20 milliseconds interval between each packet.

X#show ip sla configuration 2
IP SLAs Infrastructure Engine-III
Entry number: 2
Owner: 
Tag: 
Operation timeout (milliseconds): 5000
Type of operation to perform: icmp-jitter
Target address/Source address: 10.0.3.1/10.0.0.1
Packet Interval (milliseconds)/Number of packets: 20/10
Type Of Service parameter: 0x0
Vrf Name: 
Schedule:
   Operation frequency (seconds): 60  (not considered if randomly scheduled)
<output is truncated>

UDP Jitter and IP SLA responder

UDP is used in voice and video communications. Using UDP traffic for measurements suits better to simulate such applications. In an IP SLA operation configuration codec type can be specified, and this will define packet size and enable various voice-specific metric calculations, such as Mean Opinion Score (MOS).

Figure 2. IP SLA Responder Configuration
Figure 2. IP SLA Responder Configuration

To use the UDP Jitter destination device must also be a Cisco device with an IP SLA responder feature enabled on it. The responder’s basic configuration is completed with the single command on router Z:

Z(config)#ip sla responder

Back on the router X, IP SLA configuration is done per the example below.

X(config)#ip sla 3
X(config-ip-sla)#udp-jitter 10.0.3.1 2345 source-ip 10.0.0.1
X(config)#ip sla schedule 3 start-time now life forever
X#show ip sla statistics 
IPSLAs Latest Operation Statistics

IPSLA operation id: 3
Type of operation: udp-jitter
        Latest RTT: 1 milliseconds
Latest operation start time: 05:53:56 UTC Sun Jan 31 2021
Latest operation return code: OK
RTT Values:
        Number Of RTT: 10               RTT Min/Avg/Max: 1/1/1 milliseconds
Latency one-way time:
        Number of Latency one-way Samples: 0
        Source to Destination Latency one way Min/Avg/Max: 0/0/0 milliseconds
        Destination to Source Latency one way Min/Avg/Max: 0/0/0 milliseconds
Jitter Time:
        Number of SD Jitter Samples: 9
        Number of DS Jitter Samples: 9
        Source to Destination Jitter Min/Avg/Max: 0/1/1 milliseconds
        Destination to Source Jitter Min/Avg/Max: 0/1/1 milliseconds
Over Threshold:
        Number Of RTT Over Threshold: 0 (0%)
Packet Loss Values:
        Loss Source to Destination: 0
        Source to Destination Loss Periods Number: 0
        Source to Destination Loss Period Length Min/Max: 0/0
        Source to Destination Inter Loss Period Length Min/Max: 0/0
        Loss Destination to Source: 0
        Destination to Source Loss Periods Number: 0
        Destination to Source Loss Period Length Min/Max: 0/0
        Destination to Source Inter Loss Period Length Min/Max: 0/0
        Out Of Sequence: 0      Tail Drop: 0
        Packet Late Arrival: 0  Packet Skipped: 0
Voice Score Values:
        Calculated Planning Impairment Factor (ICPIF): 0
        Mean Opinion Score (MOS): 0
Number of successes: 1
Number of failures: 0
Operation time to live: Forever

Path operations

When measuring latency between two hosts it is useful to know how much delay is contributed by each hop along the path. Path-type SLAs work by running traceroute first and then performing echo or jitter operation against each discovered hop.

X(config)#ip sla 4
X(config-ip-sla)#path-echo 10.0.3.1 source-ip 10.0.0.1
X(config)#ip sla schedule 4 start-time now life forever

The configuration is based on the same network topology with 2 paths available to the destination.

Figure 3. IP SLA Path Operations
Figure 3. IP SLA Path Operations

The “show ip sla statistics aggregated 4 details” command will display round-trip time statistics for each hop. For example, the command output below shows statistics for the first hop in the path going via router B. The remaining hops statistics are omitted in the example below.

X#show ip sla statistics aggregated 4 details 
IPSLAs aggregated statistics

Distribution Statistics:
Bucket Range: 0 to < 20 ms
Avg. Latency: 1 ms
Percent of Total Completions for this Range: 100 %
Number of Completions/Sum of Latency: 1/1 
Sum of RTT squared low 32 Bits/Sum of RTT squared high 32 Bits: 1/0
Operations completed over threshold: 0
Start Time Index: *09:54:47.234 UTC Tue Feb 2 2021
Path Index: 3
Hop in Path Index: 1
Type of operation: path-echo
Number of successes: 18
Number of failures: 0
Number of over thresholds: 0
Failed Operations due to Disconnect/TimeOut/Busy/No Connection: 0/0/0/0
Failed Operations due to Internal/Sequence/Verify Error: 0/0/0
Failed Operations due to Control enable/Stats retrieve Error: 0/0
Target Address 172.16.100.6
<output is truncated>

Other operations

IP SLA can perform application-specific monitoring, for example, it can run HTTP or FTP operations against a remote server. For generic TCP applications, TCP operation can be used, which validates if the TCP connection can be established and how long it takes to connect to the server.

The other available operation types are DHCP (checks how long it takes to obtain an IP address) and DNS queries.

Reactions and Proactive Monitoring

In the previous sections, we’ve reviewed different types of SLA operations and how to check their operations using CLI. By using SNMP-based monitoring software, administrators can poll SLA data from routers periodically, which is a more scalable approach to monitoring. Cisco provides SNMP MIB called RTTMON that provides access to IP SLAs from monitoring software.

It is also possible for a router to send an SNMP trap or Syslog message if a certain event happens. IP SLA includes a feature called proactive threshold monitoring. To enable it IP SLA reaction must be configured.

SLA reaction configuration command references an IP SLA operation and has a mandatory parameter specifying what monitored element of SLA we want to monitor. For example, this can be a timeout or threshold-based value. Available monitored elements vary based on the type of IP SLA operation. A compatibility table is available on this page. https://www.cisco.com/c/en/us/td/docs/ios-xml/ios/ipsla/configuration/xe-16-9/sla-xe-16-9-book/sla-threshold-mon.html

The example below uses a previously configured IP SLA operation of icmp-echo type.

ip sla 1
 icmp-echo 10.0.3.1 source-ip 10.0.0.1
ip sla schedule 1 life forever start-time now

The reaction configuration below references SLA operation 1 and selects timeout as a monitored element. Then we enable simple SNMP configuration to send a trap when operations times out.

X(config)#ip sla reaction-configuration 1 react timeout action-type trapOnly threshold-type immediate
X(config)#snmp-server enable traps ipsla
X(config)#snmp-server host 10.0.0.5 PUBLIC

To test it, I’ve turned off the interface on router Z and enabled debug of SNMP packets to confirm that SNMP traps were generated by the router.

X#debug snmp packets
*Feb  4 09:41:49.232: SNMP: Queuing packet to 10.0.0.5
*Feb  4 09:41:49.232: SNMP: V1 Trap, ent rttMonNotificationsPrefix, addr 10.0.0.1, gentrap 6, spectrap 2 
 rttMonCtrlAdminTag.1 =  
 rttMonHistoryCollectionAddress.1 = 0A 00  03 01    
 rttMonCtrlOperTimeoutOccurred.1 = 2
<output is truncated>

Enhanced Object Tracking

The final section of this document addresses how a router can change its data plane operation in response to IP SLA operational status.

The feature responsible for translating the status of IP SLA operations to the data plane protocols is called Enhanced Object Tracking. First-Hop Redundancy Protocols, such as HSRP and VRRP use the tracking objects to take over or release data forwarding roles. Static and policy-based routing can also use the tracking objects to re-route around degraded paths.

EEM (Embedded Event Manager) scripts can monitor tracking object’s status changes. This makes it possible to run powerful EEM scripting in response to track status change.

A Track object can have 2 states – Up and Down. IP SLA operations can have several return codes. For the purpose of object tracking, we are interested in the 3 return codes discussed below. All other codes that are not covered in this article translate into the Down state of the Track object.

Let’s re-use the IP SLA ICMP Echo operation from the previous example and check the code of the operation. The second command in the listing shows how to check the default threshold (5000ms):

X#show ip sla statistics 1 | incl code           
Latest operation return code: OK
X#show ip sla configuration 1 | include Threshold
Threshold (milliseconds): 5000

The operation’s return code is OK, which means that the ping operation is successful and its round-trip time is within the threshold (in our network it is 1ms). OK status always translates to the UP state of the corresponding track object.

If we will turn off the remote interface on router Z, the return code will change to Timeout, as per the listing below. This is the second SLA operation code, which always translates into the Down state of the Track object.

X#show ip sla statistics 1 | incl code
Latest operation return code: Timeout

The third code that is relevant for the purpose of track operation is OverThreshold. To demonstrate it, we increased the request data size to 5000 bytes, so the operation takes longer than 1ms. We also decreased the threshold to 1ms, so the operation goes over the threshold.

The OverThreshold code translates differently to the track object state, which we will discuss in the next section.

X(config)#ip sla 2
X(config-ip-sla)#icmp-echo 10.0.3.1 source-ip 10.0.0.1
X(config-ip-sla-echo)# request-data-size 5000
X(config-ip-sla-echo)# threshold 1
X(config)#ip sla schedule 2 start-time now life forever

X#show ip sla statistics 2               
IPSLAs Latest Operation Statistics

IPSLA operation id: 2
        Latest RTT: 2 milliseconds
Latest operation start time: 09:44:48 UTC Sat Feb 6 2021
Latest operation return code: Over threshold
Number of successes: 2
Number of failures: 0
Operation time to live: Forever

IP SLA Track State vs. Reachability

track <id> ip sla <sla-id>” command creates a track object that references SLA operation. There are 2 types of track objects for SLA – reachability, and state. Let’s configure both types against the previously configured SLA 2 to see the difference.

X(config)#track 1 ip sla 2 reachability
X(config)#track 2 ip sla 2 state

X#show track 
Track 1
  IP SLA 2 reachability
  Reachability is Up
    1 change, last change 00:00:29
  Latest operation return code: Over threshold
  Latest RTT (millisecs) 2
Track 2
  IP SLA 2 state
  State is Down
    1 change, last change 00:00:17
  Latest operation return code: Over threshold
  Latest RTT (millisecs) 2

Track 1 is based on reachability and it is UP, even when the underlying IP SLA object is over the threshold. As the name suggests, we only interested in the fact that we can reach the remote side of the connection. Track 2 is state-based and it returns DOWN for the same IP SLA object. Track of the state type checks both reachability and that the IP SLA object is under the specified threshold.

Static Routes

The next listing demonstrates how to use the track objects with static routes:

X(config)#ip route 0.0.0.0 0.0.0.0 172.16.100.2 track 1 200
X(config)#ip route 0.0.0.0 0.0.0.0 172.16.100.6 track 2

X#sh ip route 0.0.0.0
Routing entry for 0.0.0.0/0, supernet
  Known via "static", distance 200, metric 0, candidate default path
  Routing Descriptor Blocks:
  * 172.16.100.2
      Route metric is 0, traffic share count is 1

The route via 172.16.100.6 is the preferred, as it has the default administrative distance of 1. The route via 172.16.100.2 is a backup route with an administrative distance of 200. However, the route table shows that the router prefers the route via 172.16.100.2.

For a route to be installed into the routing table the corresponding track must be UP. Because track object #2 is Down, the static route via 172.16.100.6 is withdrawn and the backup route is chosen and installed into the routing table.

EEM Scripts with IP SLA

The final example of this article is an EEM (Embedded Event Manager) script that adjusts the router configuration, generates a Syslog message in response to the Track state change.

The script is triggered when Track object #1 goes down, with the “event track <object-id> state down” command.

The access-list is being adjusted by the script in this example only for demonstration purposes. It can be adjusted to suit real-life requirements. For example, the script can reconfigure VPN tunnel endpoints or enable a backup interface. EEM can perform many other non-CLI actions as well.

X(config)#event manager applet TRACK-1-DOWN 
X(config-applet)#event track 1 state down
X(config-applet)#action 1 cli command "enable"
X(config-applet)#action 2 cli command "conf t"
X(config-applet)#action 3 cli command "ip access-list extended INTERNET-IN"
X(config-applet)#action 4 cli command "permit ip host 1.2.3.4 any"         
X(config-applet)#action 5 syslog msg "TEST Message"

X#show run | section ^ip access-list
<none>

To test the script, I’ve turned off the remote interface on router Z causing IP SLA and track to go down. The router generates a test Syslog message and creates an access-list, as shown in the listing below. “terminal monitor” command displays console messages into VTY lines, such as SSH or Telnet.

X#terminal monitor
*Feb  6 10:13:50.285: %TRACK-6-STATE: 1 ip sla 2 reachability Up -> Down

*Feb  6 10:13:50.530: %HA_EM-6-LOG: TRACK-1-DOWN: TEST Message

X#sh run | section ^ip access-list
ip access-list extended INTERNET-IN
 permit ip host 1.2.3.4 any

Interpret JSON Encoded Data

In this blog post, we will discuss the JavaScript Object Notation (JSON) data format. The target audience is CCNA and CCNP candidates preparing for the exams.

Interpret JSON Encoded Data

The content provides fundamental overview of the following topics:

CCNA exam

6.7 Interpret JSON encoded data

CCNP ENCOR exam

6.2 Construct valid JSON encoded file

JSON Overview

JSON is an open standard text-based file format to store and exchange serialized data. Serialization is the process of converting an object into a format that can be stored or transported to later recreate it.

JSON was originally derived from JavaScript, however, many other programming languages can interpret and generate JSON data. Figure 1 shows how JSON components fit together.

JSON text can represent one of the following values (orange and blue circles):

  • String
  • Number
  • Literal name (false, true, null)
  • Array
  • Object
Figure 1. JSON Values, Objects and Arrays
Figure 1. JSON Values, Objects and Arrays

JSON simple values

Strings, numbers, and literals

The simple values can represent some text or number and cannot contain other values. For example, below are examples of valid JSON texts:

Listing 1

"I'm a JSON"
100
true
null

As per RFC 8259, JSON text can be represented by any serialized value. Some specifications of JSON require that valid JSON text must be an object or an array.

Note that the string values must be enclosed in quotation marks.

JSON structured data values

Structural characters

JSON values that represent structured data (blue circles) created using 6 structural characters listed below:

  • Square brackets [] – beginning and end of an array
  • Curly brackets {} – beginning and end of an object
  • Colon : – Name separator
  • Comma , – Value separator

JSON allows the use of whitespaces, such as spaces, tabs, and new lines to format the text for readability. Contrasted to Python, indentation is used only for readability.

Array

An array contains zero or multiple ordered elements. Elements don’t have to be of the same type.

Listing 2

[ "abc", 23, null ]

Object

An object contains zero or multiple members, separated by commas. Each member is in the name: value format. Name must be unique within an object.

Listing 3

{ 
    "address": "192.168.8.1", 
    "mask": "255.255.255.255" 
}

Nested Objects and Arrays

Arrays and objects can contain both simple values, other arrays, and other objects.

For instance, below is the object, as we can see it starts with an opening curly brace. The object contains 2 members with name tags of “primary_address” and “secondary_address”. Each of the member’s value is another object that consists of 2 more members, named “address” and “mask”.

Listing 4

{ 
    "primary_address": 
    {
        "address": "192.168.8.1", 
        "mask": "255.255.255.255"
    },
    "secondary_address": 
    {
        "address": "192.168.9.1", 
        "mask": "255.255.255.255"
    },
}

Let’s create an array that will contain 2 objects representing addresses. The opening square bracket starts the definition of an array. Then we wrap each of the members from the previous example into curly brackets to create an object, as array stores elements – not members consisting of name: value pairs.

Listing 5

[ 
    {
        "primary_address": 
        {
            "address": "192.168.8.1", 
            "mask": "255.255.255.255"
        }
    },
        "secondary_address": 
        {
            "address": "192.168.9.1", 
            "mask": "255.255.255.255"
        },
    }
]

How to interpret JSON encoded data

In one of the previous blog posts dedicated to REST API, we’ve programmatically extracted a JSON representation of an interface from the IOS-XE router. This listing below shows several router’s interfaces, so we can have some arrays in the example.

Listing 6

{
  "Cisco-IOS-XE-native:interface": {
    "GigabitEthernet": [
      {
        "name": "1",
        "ip": {
          "address": {
            "primary": {
              "address": "192.168.7.4",
              "mask": "255.255.255.0"
            }
          }
        },
        "mop": {
          "enabled": false,
          "sysid": false
        },
        "Cisco-IOS-XE-ethernet:negotiation": {
          "auto": true
        }
      },
      {
        "name": "2",
        "shutdown": [
          null
        ],
        "mop": {
          "enabled": false,
          "sysid": false
        },
        "Cisco-IOS-XE-ethernet:negotiation": {
          "auto": true
        }
      }
    ]
  }
}

Let’s interpret this document. Figure 2 shows the structure of the JSON code from the example above.

The top-level object (#1) has a single member with the name of “Cisco-IOS-XE-native:interface”. This member’s value is another object (#2).

The object #2 also has a single member named “GigabitEthernet”, whose value is an array (#3).

Array contains 2 elements – object #4 and object #5.

Object #4 has 4 members, with the following names:

  • “name”
  • “ip”
  • “mop”
  • “Cisco-IOS-XE-ethernet:negotiation”

Member called “name” has a string value of “1”. The next member named “ip” has an object (#6) as a value. Object #6 has a single member with the name of “address” having another object (#7) as a value.

The pattern of finding array elements and object members should be apparent by now.

Figure 2. Cisco IOS-XE RESTCONF JSON interpretation example
Figure 2. Cisco IOS-XE RESTCONF JSON interpretation example

How to construct JSON encoded data

Online Tools

The easiest way to create a JSON encoded data is to use one of the available online JSON editors. For example, one is available via this URL. It automatically checks JSON file syntax, which can be useful to find a missing bracket. The other feature of this tool is the ability to auto-format code into a compact format or full format (with line breaks and indentation, as shown in the previous example).

The screenshot of the tool with JSON text from the previous example is shown below.

Figure 3. JSON Editor Online
Figure 3. JSON Editor Online

Python Collections Overview

To continue with the following examples, we recommend checking this article (URL) for a brief quick start and Python installation instructions.

Let’s discuss several Python fundamental topics before proceeding with the practical examples.

  • Data Structures: lists and dictionaries

Lists and dictionaries are examples of collections in Python. Python’s JSON module maps lists to JSON arrays, and dictionaries to JSON objects.

The syntax is identical between matching pairs of data structures, as shown in Figure 4.

Figure 4. Mapping of JSON structured data to Python collections
Figure 4. Mapping of JSON structured data to Python collections

The listing below shows an example of a list and a dictionary definition in Python.

A list is defined in Python using square brackets. Python uses None instead of null literal in JSON.

The dictionary is wrapped with curly brackets and has familiar from JSON example syntax. JSON’s name tag (value just before the colon) corresponds to a dictionary key in Python. It is followed by a colon and a value, which is in our example a string.

Listing 7

sample_list = [ "abc", 23, None ]
sample_dictionary = { "address": "192.168.8.1", "mask": "255.255.255.255" }

Let start interactive Python prompt to demonstrate how to work with lists and dictionaries.

Listing 8

c:\PythonExamples>python
Python 3.8.3 (tags/v3.8.3:6f8c832, May 13 2020, 22:20:19) [MSC v.1925 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> sample_list = [ "abc", 23, None ]
>>> sample_dictionary = { "address": "192.168.8.1", "mask": "255.255.255.255" }

Both lists and dictionaries can be passed to print() method, which will display their string representation.

Listing 9

>>> print(sample_list)
['abc', 23, None]
>>> print(sample_dictionary)
{'address': '192.168.8.1', 'mask': '255.255.255.255'}

We can access individual elements in a list using their index position.

Listing 10

>>> print(sample_list[0])
abc
>>> print(sample_list[1])
23

To extract values for a specific dictionary key, we can use the key’s name as an index.

Listing 11

>>> print(sample_dictionary["address"])
192.168.8.1
>>> print(sample_dictionary["mask"])
255.255.255.255
  • Working with files

We will save and read JSON files to and from a file saved on the disk in the next examples.

To open a file for read access in Python the following code is used:

Listing 12

with open("json_test.json","r") as json_file:
    … some code that makes use of json_file

To open the same file for write access, use “w” instead of “r” as a parameter for the open() function. Use of keyword “with” ensures that the file is properly closed after the use.

Decoding JSON in Python example

Python module called json provides JSON encoding and decoding capabilities. There are 2 methods performing these functions:

  • dumps – Python data structure to JSON text
  • loads – JSON text into Python data structure

Let’s create a text file containing JSON text from Listing 6 and save it as json_ios_xe.json.

As the next step, we will create a file named json_example.py that will have the following Python code in it.

Listing 13

import json

with open("json_ios_xe_interfaces.json", "r") as json_file:
    json_file_content = json_file.read()
decoded_json = json.loads(json_file_content)

print(decoded_json)
print()
print(type(decoded_json))

Line #1 imports json module, so we can use its feature in our code.

The code in line #3 opens our file for read-only access. The access to the file content is provided via json_file variable. The code in line #4 reads-in content of the file into a string variable.

Line #5 uses json.loads() function to read the string representation of JSON text. The returned value is assigned to the decoded_json variable. As the JSON text is a JSON object, the decoded_json object will be a Python dictionary.

Line #7 prints the Python dictionary, followed by an empty line created by line #8. Finally, line #9 prints out the type of decoded_json object, so we can validate that it is in fact a Python dictionary.

Let’s run the code and see the result.

Listing 14

c:\PythonExamples>python json_example.py
{'Cisco-IOS-XE-native:interface': {'GigabitEthernet': [{'name': '1', 'ip': {'address': {'primary': {'address': '192.168.7.4', 'mask': '255.255.255.0'}}}, 'mop': {'enabled': False, 'sysid': False}, 'Cisco-IOS-XE-ethernet:negotiation': {'auto': True}}, {'name': '2', 'shutdown': [None], 'mop': {'enabled': False, 'sysid': False}, 'Cisco-IOS-XE-ethernet:negotiation': {'auto': True}}]}}

<class 'dict'>

Encoding to JSON in Python example

In this example, we will use the dictionary created in the previous example, change the IP address to “192.168.7.5” and will encode it as another JSON file.

The first task is to identify the full path to the IP address. We have several nested layers of hierarchy within the outer-most dictionary. To access inner dictionaries and lists we will append [<index_or_key_name>] to the parent identifier.

Full path to value of ‘address’ key will be:

Listing 15

decoded_json['Cisco-IOS-XE-native:interface']['GigabitEthernet'][0]['ip']['address']['primary']['address']

In the example above the index of [0] is used, as the ‘GigabitEthernet’ key has the value of a list and we are interested in the first element.

Below is the full listing of a program code that changes the IP address and saves it as a new JSON file on the disk.

Listing 16

import json

with open("json_ios_xe.json", "r") as json_file:
    json_file_content = json_file.read()

decoded_json = json.loads(json_file_content)

decoded_json['Cisco-IOS-XE-native:interface']['GigabitEthernet'][0]['ip']['address']['primary']['address'] = \
    "192.168.7.5"

encoded_json_compact = json.dumps(decoded_json)
encoded_json_indented = json.dumps(decoded_json, indent = 4)

with open("json_ios_xe_compact.json", "w") as json_file:
    json_file.write(encoded_json_compact)

with open("json_ios_xe_indented.json", "w") as json_file:
    json_file.write(encoded_json_indented)

Line #8 sets the value to a new IP address. Lines #11 and #12 create a string containing JSON text, it passes our modified dictionary called decoded_json to json.dumps() function. The example demonstrates that the named parameter called “indent” can be passed to the dumps() method to perform the formatting of the JSON file.

Line #15 and #18 saving the resulted text to files on the disk.

Let’s run the code and see the result.

Listing 17

c:\PythonExamples>python json_example.py

Two new files are created in c:\PythonExamples folder, as shown in the screenshot below.

Figure 5. JSON text decoded by Python's json.dumps()
Figure 5. JSON text decoded by Python’s json.dumps()

Self-Test Questions

List 6 types of value types that JSON text can represent?
String, number, Boolean (false, true), null, array, and object.
Describe JSON array and the process of defining one.
A JSON array contains ordered elements and defined using square brackets. For example, [ “abc”, 23, null ]
Describe JSON object and the process of defining one.
A JSON object contains members separated by a comma. Each member has a name and value separated by a colon. It is defined using curly brackets. For example, { “address”: “192.168.8.1”, “mask”: “255.255.255.255” }
Name Python types that are mapped to JSON's array and object
Python’s list maps to JSON array, and Python’s dictionary maps to a JSON object
What Python's module is responsible for encoding and decoding of JSON-formatted data?
json module. To decode use json.loads() and to encode – json.dumps().

Interpret Basic Python Components and Scripts

In this blog post, we will provide an introduction to Python components and scripts in the context of Cisco certification. We will show how to get started with Python and explain the most commonly used elements of Python scripts – variables, functions, program flow, conditional logic, and “for” loops.

Interpret Basic Python Components and Scripts

The content aims to help CCNP/CCIE Enterprise track candidates to prepare for the ENCOR exam, which includes the following topic:

6.1 Interpret basic Python components and scripts

Many CCNP tracks have automation sections that assume some knowledge of Python. DevNet track expects more extensive knowledge in Python.

Python Installation

Python is an interpreted language, which means that the code of a program is not pre-compiled into an executable that contains machine instructions. Python code can be opened and edited with any text editor. Python programs have a .py extension.

To run a Python code an interpreter is required. It reads the code and converts it into machine instructions.

Python is available for different platforms. Python 3.x is the recommended version and we will use it in our examples.

To download Python installation files navigate to this URL. Start the installer.

We use Windows 10 in our examples. Enable the checkbox “Add Python 3.x to PATH” and press Install Now.

Figure 1. Python Installation Options
Figure 1. Python Installation Options

Start Windows CLI utility by starting typing “Command Prompt”. Once started type in the following command to confirm that Python interpreter is available.

Microsoft Windows [Version 10.0.18362.836]
(c) 2019 Microsoft Corporation. All rights reserved.

C:\PythonExamples>python --version
Python 3.8.3

Keep the command prompt window opened.

Hello World!

We will start with a simple “Hello World!” example.

Open a text editor, such as Notepad, and type-in the following code:

print("Hello World!")

The example uses a built-in print() function that displays a message on the screen.

Save the file as hello_world.py in a folder on your computer. To run the program, we will pass the full file name to python interpreter:

C:\PythonExamples>python c:\PythonExamples\hello_world.py
Hello World!

Variables

A variable stores some value, which can be accessed in the code by using its name. In Python, variables are not declared and can be used by assigning a value to them.

Let’s add a few more lines to the hello_world file. The new code creates a line number variable that is changed after each use. First two times it was statically set to 2 and 3, and in the line, before the last, we’ve just incremented its value by 1. The print function is being provided with 2 arguments – descriptive text and the line number variable.

print("Hello World!")
line_number = 2
print("This is the line number", line_number)
line_number = 3
print("This is the line number", line_number)
line_number = line_number + 1
print("This is the line number", line_number)

When the program is launched the following output is displayed on the screen.

C:\PythonExamples>python c:\PythonExamples\hello_world.py
Hello World!
This is the line number 2
This is the line number 3
This is the line number 4

Functions

A function minimizes the amount of duplicate code. It can also provide better structure and improve the readability of program code, by wrapping related logic under the function definition, which can be called by a descriptive name from other places of the program.

Let’s adjust our program to demonstrate the use of functions.

def line_number_printer(number):
    print("This is the line number", number)

def calculate_next_line_number(previous_number):
    return previous_number + 1

print("Hello World!")
line_number = 2
line_number_printer(line_number)
line_number = calculate_next_line_number(line_number)
line_number_printer(line_number)
line_number = calculate_next_line_number(line_number)
line_number_printer(line_number)

The program produces exactly the same output as the code in the previous example.

We have introduced 2 functions:

  • line_number_printer(number)
  • calculate_next_line_number(previous_number)

Figure 2 shows how the functions are defined and used in the example above. Not all lines from the example are shown for brevity.

Figure 2. Python Functions Example
Figure 2. Python Functions Example

Let’s go through the diagram and discuss each element:

  1. A function’s definition must precede its use. The code within the definition is not executed unless it is called.
  2. Function definition starts with a keyword “def”.
  3. The function name should be in lower case with underscore used as a word separator. Python’s style guide is called PEP 8. It explains different elements of style, such as the naming convention and how the code must be formatted (https://www.python.org/dev/peps/pep-0008).
  4. A function can accept a value as an input in the form of parameter. Variable name in parentheses stores value supplied when the function was called. This variable is available for use within the function body.
  5. The line containing function definition ends with a colon showing that function statements will follow in the next lines.
  6. The code statements within a function are indented. PEP 8 recommends the use of spaces for indentation instead of tabs. Also, 4 spaces should separate each indentation level.
  7. A function can be invoked to perform some action without returning any values to the caller. It can also return a value; such as a result of a calculation or a success code back to the caller. To create such a function, a statement starting with keyword return is used. When this statement is encountered, function execution stops.

Conditional Logic

Conditional logic statements allow us to perform certain actions based on an evaluation result of a condition. Let’s modify our example, so the line_number_print function displays different strings depending on whether the number is odd or even. The listing below shows the modifications made, the remaining code is not changed.

def line_number_printer(number):
    if number % 2 == 0:
        print("This is the line number", number, "and it is even")
    else:
        print("This is the line number", number, "and it is odd")

When the program is launched the following output is displayed on the screen.

C:\PythonExamples\>python c:\PythonExamples\hello_world.py
Hello World!
This is the line number 2 and it is even
This is the line number 3 and it is odd
This is the line number 4 and it is even

Figure 3 shows how conditional logic is used in the example above.

Figure 3. Python Conditional Logic Example
Figure 3. Python Conditional Logic Example

Let’s go through the diagram and discuss each element:

  1. “if” keyword is followed by a logical test that can be either True or False.
  2. If the test is evaluated as True, the statement (or multiple statements) under the “if” section is executed.
  3. As with the functions, the body of “if” or “else” sections comprises of indented statements.
  4. If the test is evaluated as False, the statement (or multiple statements) under the “else” section is executed.

for Loops

The “for” loops can be used to apply an action to each element of a collection. For example, we can store a list of switch interfaces in a list. To check the status of each of these interfaces we can use the “for” loop to iterate through the list and then run a command against each of the interfaces.

Let’s rewrite our program using “for” loops to automatically assign line numbers.

The listing below shows the complete code, as we removed the line calculation function and multiple calls to print function.

def line_number_printer(number):
    if number % 2 == 0:
        print("This is the line number", number, "and it is even")
    else:
        print("This is the line number", number, "and it is odd")

print("Hello World!")
for line_number in range(2, 5):
    line_number_printer(line_number)

When the program is launched the same output is displayed on the screen.

C:\PythonExamples>python c:\PythonExamples\hello_world.py
Hello World!
This is the line number 2 and it is even
This is the line number 3 and it is odd
This is the line number 4 and it is even

Figure 4 shows how “for” loop is used in the example above.

Figure 4. Python "for" loop Example
Figure 4. Python “for” loop Example

Let’s go through the diagram and discuss each element:

  1. “for” keyword is followed by a variable name that will be changing its value on each pass.
  2. “in” keyword is followed by a list of values that will be assigned one at a time to the “for” variable on each iteration.
  3. Statements that perform actual work during each cycle are indented under the “for” loop.

Not shown in the example, “break” keyword stops loop processing and continues with the code following the loop. Similarly, the “continue” keyword stops the current pass processing, but in contrast to “break”, it starts the next cycle of the loop.

Self-Test Tasks:

Task 1

Write a function that accepts a number and prints it out followed by “is the number passed as a parameter”.

Task 2

Write a function that accepts a number and prints out “Greater than 10” or “Less or equal than 10” depending on the number that was provided. The greater operator is “>” and less or equal is “<=”.

Task 3

Write a “for” loop that iterates over a list of interfaces Ethernet1/1, Ethernet1/2, and Ethernet1/3 and prints out the output below. To supply interfaces for “for” loop, use a list [ “Ethernet1/1”, “Ethernet1/2”, “Ethernet1/3” ]

interface Ethernet1/1
 description Added by Automation Script
 no shutdown
interface Ethernet1/2
 description Added by Automation Script
 no shutdown
interface Ethernet1/3
 description Added by Automation Script
 no shutdown

Self-Test Answers:

Task 1

def print_number(number):
    print(number, "is the number passed as a parameter")

Task 2

def compare_number_to_ten(number):
    if number > 10:
        print("Greater than 10")
    else:
        print("Less or equal than 10")

Task 3

for interface_name in [ "Ethernet1/1", "Ethernet1/2", "Ethernet1/3" ]:
    print("interface", interface_name)
    print(" description Added by Automation Script")
    print(" no shutdown")

Describe characteristics of REST-based APIs

In this blog post, we will discuss REST-based APIs. We will also demonstrate how to use such APIs with step-by-step scenarios using a Cisco virtual router running on the ESXi platform.

This article aims to help CCNA candidates in preparing for the following exam topic:

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

APIs and Representational State Transfer (REST)

Application Programming Interface (API)

API of an application or a service specifies how other applications can access and change its information. For example, a service may expect certain parameters to be specified when a client application makes a request. The service generates some output as a response, which is also part of API.

A network device manufacture develops and maintains API. CCNA candidates should understand how to use APIs from the client perspective. Automation scripts and software use APIs that network devices expose.

Command-Line Interface (CLI) cannot be classified as API. It provides means to change how a device operates, but its primary purpose is to interact with a user, i.e. not with another program. CLI, however, can be used in automation scripts, which interactively send and parse command output.

SNMP operation fits the definition of API. However, it didn’t receive wide adoption in network automation and is mostly used in read-only monitoring.

Cisco devices and controllers expose RESTful APIs, i.e. APIs that meet specific architectural criteria. We will discuss this type of API in the following section.

RESTful API

REST defines a set of architectural guidelines that were defined by Roy Fielding in his dissertation.

REST is not a protocol and doesn’t provide specific implementation details. For example, it doesn’t mandate the use of HTTP, which is, however, is most often used and often associated with REST APIs.

REST defines a set of constraints that must be met for a web service to be considered RESTful. The full list of constraints is:

  • Must have client-server architecture.
  • RESTful services must have a uniform interface.
  • The client must track the state of the session and send request containing all information required to process such a request. The server must not store user session context information.
  • The server must state whether information can be cached on the client.
  • The system must have a hierarchical layered design.
  • The server can send executable code to a client to extend its functionality.

RESTful API constraints provide multiple benefits for an application and are important for an API designer to follow. However, for a network engineer, the main areas of focus are centered around how to access and change information behind API.

REST Resources and Representation

In REST API a resource is any type of information that can have a name. For example, a network interface or an access list can be used as resources in API.

A resource is identified with a Uniform Resource Identifier (URI). Type of URI that specifies a location and access protocol of a resource is called Unified Resource Locator (URL). When a client sends a request to REST API, it must include a resource identifier. For example, if HTTP is used as protocol, the URL of https://fastreroute.com/category/ccna consists of the URI scheme of HTTPS, followed by colon, authority “//”, hostname – fastreroute.com, and resource identifier (or path) – /category/ccna.

Representation of a resource is a self-describing state of a resource at a specific moment. The server provides a representation of a resource to the client, which can perform different operations on the resource. For example, the representation of the resource identified with the URL in the previous paragraph is an HTML page that contains all CCNA posts of the blog. REST APIs can return representation as a serialized object, for example, in (JavaScript Object Notation) JSON format.

CRUD and HTTP Verbs

CRUD stands for 4 generic types of operations that can be applied to data:

  • Create
  • Read
  • Update
  • Delete 

HTTP request methods, also called verbs, can be mapped to CRUD operations. For example, in an HTTP-based RESTful API, a client can change the parameters of a network interface by using the HTTP PATCH method. We will show how it can be done in the example section.

HTTP GET method corresponds to Read operation. The server responds with a representation of a resource identified by URI.

HTTP POST verb Creates a child or subordinate to resource specified in URI.

HTTP PUT maps to both Update and Create operations. If a resource specified in the PUT request exists on the server, it should be replaced with the one in the request. If the resource doesn’t exist, PUT can create it.

HTTP PATCH verb can also perform the Update operation. PATCH contains instructions on how to update a resource, while PUT contains a modified copy of a resource.

HTTP DELETE maps to Delete operation.

REST API Example: CSR1000v

Let’s apply concepts from the previous section to practice. The next few sections will show how to perform each of CRUD operations with REST-like API provided by Cisco IOS-XE routers.

This API is based on RESTCONF. It can return the representation of resources in XML or JSON formats. RESTCONF uses YANG, which is modeling language describing a router’s configuration and operation states.

Both RESTCONF and YANG are described in RFCs:

IOS-XE Configuration for RESTCONF

In our example, we will generate API requests to a CSR1000v IOS-XE router running on ESXi.

Our router runs IOS-XE version 16.9.5 with the following configuration applied:

interface GigabitEthernet1
 ip address 192.168.7.4 255.255.255.0
 no shutdown
aaa new-model
aaa authentication login default local
aaa authorization exec default local

username admin secret ciscocisco
username admin privilege 15
enable secret ciscocisco

ip http server
ip http authentication local
ip http secure-server
restconf

Refer for details to the Cisco configuration guide, which is available via this URL.

Postman Client Setup

We will use free tier features of software called Postman (https://www.postman.com/).

Postman helps with testing and discovery of API prior to writing automation programs. The automation scripts can be written using programming languages, such as Python with requests library.

Download the software for the platform of your choice. We use the Windows version of Postman in the next examples and the screenshots.

Start Postman and disable SSL certificate validation, as we are going to use the router’s IP address and self-signed certificate in our examples:

Figure 1. Postman - Disable SSL Certificate Verification
Figure 1. Postman – Disable SSL Certificate Verification

Read with HTTP GET

In the first example, we will send a simple GET request to obtain a list of interfaces of the router.

Figure 2. REST API READ
Figure 2. REST API READ

The next figure shows the sequence of steps creating the request in Postman that returns the list of interfaces of the router. The username and password values must match ones configured on the router.

In this example, the URL of https://192.168.7.4/restconf/data/Cisco-IOS-XE-native:native/interface/ consists of the following components:

  • https – URI scheme and protocol
  • // – authority
  • 192.168.7.4 – hostname or IP address of the router
  • /restconf/data/Cisco-IOS-XE-native:native/interface/ – path or resource ID
Figure 3. Postman –GET Request Parameters
Figure 3. Postman –GET Request Parameters

The result of the request is shown in the next screenshot. The server replied back with a 200 OK message and a representation of its interfaces in XML format.

Figure 4. Postman – Read list of the Router's Interfaces in XML Format
Figure 4. Postman – Read list of the Router’s Interfaces in XML Format

To switch to JSON we can adjust the request by modifying Headers as shown in Figure 5. Accept key is set to value of application/yang-data+json. The response looks very similar to the one in Figure 4, as both XML and JSON represent the same resource – a list of interfaces of the router.

Figure 5. Postman – Read list of the Router's Interfaces in JSON Format
Figure 5. Postman – Read list of the Router’s Interfaces in JSON Format

Create new interface with HTTP POST

As the next step, let’s create a new loopback interface using the HTTP POST verb. Figure 6 demonstrates a message exchange between the client using URI representing a list of interfaces and the POST method containing the JSON representation of the new loopback interface. The server returns HTTP response with the code of 201 (created).

Figure 6. Cisco IOS-XE REST API Create an Interface with HTTP POST
Figure 6. Cisco IOS-XE REST API Create an Interface with HTTP POST

Figure 7 shows Postman configuration for this request.

Figure 7. Postman - Create an Interface with HTTP POST
Figure 7. Postman – Create an Interface with HTTP POST

The listing below shows JSON representation of the interface:

{
  "Cisco-IOS-XE-native:Loopback": {
    "name": "1",
    "description": "Test",
    "ip": {
      "address": {
        "primary": {
          "address": "192.168.8.1",
          "mask": "255.255.255.255"
        }
      }
    }
  }
}

The router has its configuration updated with new Loopback1 interface:

ROUTER#show run interface Loopback1
!
interface Loopback1
 description Test
 ip address 192.168.8.1 255.255.255.255
!

Update interface description with HTTP PATCH

In this example, we will create a query that sets the GigabitEthernet1 interface’s description. Figure 8 shows the message exchange between the PC and the router. URI includes interface name, as PATCH is used to apply partial updates to an existing interface.

Figure 8. REST API Update with HTTP PATCH
Figure 8. REST API Update with HTTP PATCH

Postman query configuration steps are shown in Figure 9. Note that authorization settings must be set in the same way as done in the HTTP GET example.

Figure 9. Postman – Updating Interface Description using HTTP PATCH
Figure 9. Postman – Updating Interface Description using HTTP PATCH

The listing below shows JSON representation of the description change:

{
  "Cisco-IOS-XE-native:GigabitEthernet": {
    "description": "Very Important Interface",
  }
}

The router has its configuration updated with a description:

ROUTER#show run interface GigabitEthernet1
!
interface GigabitEthernet1
 description Very Important Interface
 ip address 192.168.7.4 255.255.255.0
 negotiation auto
 no mop enabled
 no mop sysid
!

Delete interface description with HTTP DELETE

The final example will delete the Loopback interface using the HTTP DELETE verb. Figure 8 shows the message exchange, which identifies the resource that we want to delete.

Figure 8. REST API Delete with HTTP DELETE
Figure 8. REST API Delete with HTTP DELETE

Figure 9 shows configuration parameters in Postman.

Figure 9. Postman – Deleting Interface with HTTP DELETE
Figure 9. Postman – Deleting Interface with HTTP DELETE

And the listing below demonstrates that the interface doesn’t exist anymore:

Router#show run interface Loopback1
                                  ^
% Invalid input detected at '^' marker.

Self-Test Questions

What is REST and RESTful API?
REpresentational State Transfer (REST) is an architectural style that defines a set of constraints to create APIs. RESTful API is an API that meets all the constraints.
Does RESTful API have to be HTTP-based?
No, REST doesn’t mandate the use of any specific protocols.
What is the difference between Resource and Representation in REST?
A resource is a named piece of information, while a representation of the resource is a description of the resource at a specific moment.
Map CRUD operations to HTTP verbs
Create – POST or PUT.
Read – GET.
Update – PATCH or PUT (by replace).
Delete – DELETE