Understanding JSON

Nearly every API response you'll ever look at is JSON. Here's how to actually read one.

1. What JSON is, and why APIs use it

JSON — JavaScript Object Notation — is a plain-text way of writing down structured data: names paired with values, organised into nested groups. Despite the name, it isn't limited to JavaScript; effectively every programming language has a built-in or standard-library way to read and write it, which is exactly why APIs settled on it as the default response format.

Before JSON became the default, APIs commonly used XML — verbose, tag-based, and noticeably more annoying to both write and parse by hand. JSON won because it maps almost directly onto the data structures programmers already use in memory (dictionaries/objects and lists/arrays), so there's very little translation work between "what the API sent" and "what your code can use."

2. The six data types

Every value in a JSON document is exactly one of six types — no more, no less:

"string"
Text, always in double quotes — never single quotes. "London"
42
A number — no quotes, and no distinction between integers and decimals. 18.4
true / false
A boolean — always lowercase, never quoted.
null
Explicitly "no value" — different from an empty string or the field being missing entirely.
{ }
An object — a group of key/value pairs, like a labelled folder of facts.
[ ]
An array — an ordered list of values, which can themselves be any of these six types.

3. Objects vs. arrays

The two container types look similar but mean different things, and mixing them up is the single most common beginner error when reading API responses.

An object: labelled fields

Curly braces. Every value has a name. Order doesn't matter — you always access a field by its key, not its position.

{
  "id": 42,
  "name": "Spoon-Knife",
  "is_private": false
}

An array: an ordered list

Square brackets. No names — just position. You access an item by its index, starting at 0.

[
  "HTML",
  "CSS",
  "JavaScript"
]
The tell: does order matter? If shuffling the entries would lose information, it's an object (each value is tied to its name). If shuffling would just change which item is "first," it's an array (the position itself might matter — e.g. "most recent" — but no name is attached).

4. Reading nested JSON

Real API responses combine both types, several levels deep. Here's a (slightly trimmed) response shape you might get back from a weather API — annotated so you can see exactly how to read it:

{
  "city": "London", // a string, directly on the top object
  "current": { // an object nested inside the top object
    "temp_c": 18.4,
    "conditions": "overcast"
  },
  "forecast": [ // an array nested inside the top object
    { "day": "Tue", "high_c": 21 }, // index 0: an object inside the array
    { "day": "Wed", "high_c": 19 } // index 1: another object inside the array
  ]
}

To get Wednesday's high temperature, you'd read it as a path: "the top object's forecast field, index 1 of that array, that object's high_c field" — in code, that's simply data.forecast[1].high_c. Every nested JSON structure reads the same way: follow the field names and indices one level at a time.

5. Mistakes that break beginners' code

JSON's syntax is stricter than it looks — these are the errors that most often turn into "invalid JSON" parse failures, usually from hand-writing a request body rather than reading a response (responses from real APIs are always valid JSON already):

MistakeWrongRight
Single quotes {'name': 'London'} {"name": "London"}
Unquoted keys {name: "London"} {"name": "London"}
Trailing comma {"a": 1, "b": 2,} {"a": 1, "b": 2}
Comments {"a": 1} // note Not supported at all — strip comments before sending
"undefined" is not a JSON value JavaScript's undefined has no JSON equivalent — if a field genuinely has no value, JSON represents that as null, never as the bare word undefined. Trying to send undefined in a request body will either error or silently drop the field, depending on your JSON library.

6. Reading a response in code

JavaScript

fetch parses JSON for you with one method call:

const res = await fetch('https://api.example.com/weather?city=London') const data = await res.json() // parses the JSON body into a plain object console.log(data.current.temp_c) // 18.4 console.log(data.forecast[1].high_c) // 19

Python

The requests library does the same job — JSON arrives as a plain dict/list:

import requests res = requests.get('https://api.example.com/weather', params={'city': 'London'}) data = res.json() print(data['current']['temp_c']) # 18.4 print(data['forecast'][1]['high_c']) # 19

Command line

curl fetches the raw response; pipe it through jq to filter and pretty-print it without writing any code at all — handy for poking at an API before you commit to a language:

curl -s 'https://api.example.com/weather?city=London' | jq '.forecast[1].high_c' # 19
Real example Our own Case Law Search app does exactly this three-step read — fetch, parse, index into a nested array — against the CourtListener API's response for every search a visitor runs; the code in Car Lookup does the same against NHTSA's nested recalls-per-VIN data. Neither app does anything more exotic than data.results[i].field.

Ready to try it on a real response?

Every API page in our catalog documents its exact response shape — pick one and read it live.

Browse all APIs Next: what is an API key?

Continue learning