Objective 6.7

Recognize components of JSON-encoded data

Why JSON matters

JSON (JavaScript Object Notation, pronounced “jay-son”) is the default data format for REST APIs, including every Cisco controller API. Almost any automation work involves reading JSON responses and writing JSON request bodies, and the exam will show you a JSON snippet and ask what it represents or what the value of a particular key is. JSON is also the language of the exam’s “recognize components” questions, so the vocabulary must be precise.

JSON is plain text, is language-independent (every programming language can read it), and is easy for both humans and machines to parse. It was derived from JavaScript object syntax but has nothing to do with running JavaScript.

The six JSON data types

Type Looks like Rules
Object { "key": value, "key2": value2 } Curly braces; an unordered collection of key/value pairs; keys are always strings in double quotes; pairs separated by commas
Array [ value, value, value ] Square brackets; an ordered list of values; values separated by commas; values may be of mixed types
String "GigabitEthernet1/0/1" Text in double quotes only; backslash escapes such as \" and \n
Number 42, -7, 3.14, 1.5e3 No quotes; integers or decimals; no leading zeros; no hexadecimal
Boolean true or false Lowercase, no quotes
null null Lowercase, no quotes; represents “no value”

Two of these, object and array, are containers that can hold any of the six types, including other objects and arrays. That is how JSON represents complex, nested information. The other four (string, number, boolean, null) are primitive values.

A first example

{
  "hostname": "SW1",
  "model": "C9300-48P",
  "uptimeDays": 142,
  "isReachable": true,
  "lastError": null,
  "vlans": [10, 20, 30]
}

Reading this out loud: it is an object (the outer braces) with six key/value pairs. "hostname" has the string value "SW1". "uptimeDays" has the number value 142 (no quotes). "isReachable" has the boolean value true. "lastError" has the value null. "vlans" has an array value containing three numbers.

Nesting

Values can be objects or arrays, and those can contain more objects and arrays, to any depth. This is how a list of interfaces, each with several properties, is represented.

{
  "device": {
    "hostname": "R1",
    "mgmt": {
      "ip": "10.0.0.1",
      "mask": "255.255.255.0"
    }
  },
  "interfaces": [
    {
      "name": "GigabitEthernet0/0",
      "ip": "192.168.1.1",
      "enabled": true,
      "description": "LAN"
    },
    {
      "name": "GigabitEthernet0/1",
      "ip": "203.0.113.2",
      "enabled": false,
      "description": "WAN"
    }
  ],
  "ospf": {
    "processId": 1,
    "routerId": "1.1.1.1",
    "areas": [0]
  }
}

How to navigate this:

  • The value of device is an object. Inside it, hostname is "R1" and mgmt is another object.
  • The value of device then mgmt then ip is "10.0.0.1". Programmers write this path as device.mgmt.ip or, in Python, data["device"]["mgmt"]["ip"].
  • The value of interfaces is an array containing two objects.
  • Arrays are indexed starting at 0. So interfaces[0] is the first interface object, and interfaces[0].name is "GigabitEthernet0/0". interfaces[1].enabled is false.
  • ospf.areas is an array with a single number in it, [0]. Note that [0] (an array containing zero) is different from 0 (a number).

More “what is the value” exercises

Study this Catalyst Center-style response and answer the questions that follow (answers are right below).

{
  "response": [
    {
      "hostname": "CORE-SW1",
      "managementIpAddress": "10.1.1.1",
      "softwareVersion": "17.9.4",
      "role": "CORE",
      "upTime": "45 days, 3:12:08.00",
      "interfaceCount": "54",
      "errorCode": null,
      "tags": []
    },
    {
      "hostname": "ACCESS-SW7",
      "managementIpAddress": "10.1.1.17",
      "softwareVersion": "17.9.4",
      "role": "ACCESS",
      "upTime": "2 days, 17:05:44.00",
      "interfaceCount": "26",
      "errorCode": "SNMP_TIMEOUT",
      "tags": ["floor2", "poe"]
    }
  ],
  "version": "1.0"
}
  1. What type of value is response? An array (square brackets) containing two objects.
  2. What is the value of hostname in the second object? "ACCESS-SW7".
  3. What data type is the value of interfaceCount? A string, because it is in double quotes ("54"), even though it looks like a number. This is a common trick.
  4. What is errorCode for CORE-SW1? null.
  5. How many elements are in tags for CORE-SW1? Zero; [] is an empty array.
  6. What is tags[1] for ACCESS-SW7? "poe" (index 1 is the second element).
  7. How many top-level keys does the outer object have? Two: response and version.

JSON syntax rules and common errors

JSON is strict. A single mistake makes the whole document invalid, and a REST API will respond with 400 Bad Request. The rules and the mistakes that break them:

Rule Valid Invalid (and why)
Keys must be strings in double quotes {"name": "SW1"} {name: "SW1"} (unquoted key; legal in JavaScript, not in JSON)
Strings use double quotes only {"name": "SW1"} {'name': 'SW1'} (single quotes are not JSON; Python prints dictionaries this way, which causes confusion)
No trailing comma after the last item [10, 20, 30] [10, 20, 30,] (trailing comma)
Booleans and null are lowercase, unquoted "up": true "up": True (Python style) or "up": "true" (that is a string, not a boolean)
Numbers are unquoted "cost": 10 "cost": "10" is valid JSON but the value is a string, not a number
Every opening brace/bracket must be closed {"a": [1, 2]} {"a": [1, 2} (mismatched)
Colon between key and value, comma between pairs {"a": 1, "b": 2} {"a": 1 "b": 2} (missing comma) or {"a" = 1} (equals sign)
No comments (none) // comment or # comment inside JSON is invalid
Duplicate keys should be avoided {"a": 1, "b": 2} {"a": 1, "a": 2} (behavior undefined; most parsers keep the last)

Whitespace (spaces, tabs, newlines) between elements is ignored, so the following is exactly the same as the multi-line first example: {"hostname":"SW1","uptimeDays":142,"isReachable":true}. Indentation is only for human readability.

Key order inside an object is officially not significant. {"a": 1, "b": 2} and {"b": 2, "a": 1} carry the same information. Order inside an array is significant: [10, 20] and [20, 10] are different.

JSON compared with XML and YAML

Feature JSON XML YAML
Structure markers {} and [] Opening and closing tags Indentation and -
Quotes on strings Required (double) Not used Optional
Comments Not allowed <!-- --> #
Data types String, number, boolean, null, object, array Everything is text unless a schema says otherwise Same as JSON plus more
Main use REST APIs NETCONF, SOAP, older APIs Ansible, config files
Verbosity Medium High Low