JSON, and why everything speaks it

The format your API returns, what it can represent, and the three things it cannot.

4 min read🧭 Programming Foundations

JSON is how two programs that share no code agree on what data means. It won because it is small, it is text you can read, and it has almost no features — which turns out to be the point.

The whole format

There are six kinds of value, and that is the entire specification:

json
{
  "name": "Alice",
  "age": 30,
  "active": true,
  "manager": null,
  "tags": ["java", "backend"],
  "address": { "city": "Pune", "postcode": "411001" }
}

A string in double quotes. A number. true or false. null. An array in [], ordered, values of any kind. An object in {}, keys always strings, values of any kind.

Objects and arrays nest, which is where all the expressiveness comes from. There is nothing else — no dates, no comments, no trailing commas, no single quotes.

The three things it cannot represent

This is the part worth knowing before you need it.

There is no date type. A date in JSON is a string, and the two programs must agree on its shape. The agreement worth having is ISO-8601 in UTC:

json
{ "createdAt": "2026-09-11T20:38:55Z" }

The Z means UTC. "11/09/2026" is ambiguous — it is September in India and November in the United States — and that ambiguity has caused real incidents.

Numbers have no declared precision. 0.1 in JSON is just digits; what it becomes depends on the reader. Most parsers make it a floating-point double, which cannot represent 0.1 exactly — and "not exactly" is more concrete than it sounds:

plaintext
what 0.1 really is: 0.1000000000000000055511151231257827021181583404541015625
0.1 + 0.2         = 0.30000000000000004
19.99 * 100       = 1998.9999999999998
(int)(19.99*100)  = 1998

Read the last line twice. Nineteen ninety-nine multiplied by a hundred, truncated to an integer, is 1998. One paisa, gone, with no error and no warning — and it will happen on every order until somebody reconciles the ledger and finds the gap.

So for money the convention is either a string ("19.99") or an integer count of the smallest unit (1999 paise). Both are ugly and both are correct.

Large integers have the same problem from the other end. JavaScript numbers are the same doubles, so integers are exact only up to 2⁵³ − 1 — and a JSON parser is where you meet that:

plaintext
sent    : {"id": 9007199254740993, "also": 9007199254740992}
parsed  : {"id":9007199254740992,"also":9007199254740992}
equal?  : true

Two different IDs went in. One came out, twice. And === now insists they are the same record — which is a data-loss bug that no amount of careful code downstream can detect, because by then the difference is gone. This is why IDs in JSON are usually strings.

There are no comments. Deliberately — JSON is for data exchange, not configuration. That is why configuration files tend to be YAML instead.

Objects and arrays are not interchangeable

An easy mistake with a real cost:

json
{ "1": "a", "2": "b" }        object: keys, unordered by definition
[ "a", "b" ]                   array: ordered, positional

An object's keys have no guaranteed order. Most parsers preserve insertion order in practice, and nothing requires them to. If order matters, use an array. If lookup by name matters, use an object. Using an object as a list-with-numbers gets you both problems at once.

What a program does with it

Two operations, and they have names you will see in every stack trace:

  • Parsing (or deserialising): text → an object your language understands.
  • Serialising: an object → text.

In Java that is a library's job — Jackson, almost always — and you rarely write either by hand. What you do write is the shape: a class whose fields match the JSON you expect. The library fills it in, and complains when the shape does not match.

Reading JSON you did not write

Two skills, both cheap to acquire.

Format it. JSON from an API is one long line. Pipe it through a formatter and it becomes readable:

bash
curl -s https://code10x.in/api/me | python3 -m json.tool

Query it. jq is the standard tool and worth the twenty minutes:

bash
curl -s https://api.example.com/orders | jq '.[] | .customer.name'

That is "for each element of the top-level array, give me customer.name". The syntax follows the structure, which is why it is easy to guess once you have seen three examples.

Misconceptions

  • "JSON is a JavaScript thing." It came from JavaScript's syntax and is now a language-neutral format with a short specification. Java, Go, Python and everything else read it natively.
  • "Single quotes are fine." They are not JSON. Neither is a trailing comma, nor an unquoted key, nor a comment. A parser that accepts them is being lenient, and something downstream will not be.
  • "If it parses, it is valid." Parsing checks syntax. Whether the data makes sense — required fields, sane values, a date that is really a date — is your validation, and nothing does it for you.
Progress is saved on this device and to your account when signed in.