The labs on this site need JavaScript to run. The same content is written out below.
Fundamentals › Networking
JSON
What does JSON look like, and what mistakes make it unreadable?
When programs exchange data (for example, when a server sends member information to a browser), they cannot send an object in memory as it is. So they write it out as text by an agreed set of rules, and the receiving side reads that text and builds an object in its own language again. JSON is the most widely used set of rules. What you see in the code box is the JSON text itself. Inside { }, write "name": value pairs joined by commas. Wrap names and string values in double quotes, and write numbers without quotes. [ ] is an array of several values. Whether there are quotes decides the kind of the value, so 30 is a number and "30" is a string. In this lab you change the quotes around the name, the value of age, and the commas one at a time, and feed the same text to two parsers (programs that read text and build an object): JSON.parse in Node.js and Jackson in Java. You see whether the text can be read and what kind of value the age that was read is. JSON has no syntax for comments, so the code box shows the text only, with no explanations.
Checked against real execution · Fed the characters of all 18 combinations as they are to JSON.parse in Node.js 24.18.0 and to Jackson 3.1.5 (default settings) and checked them
Concepts in this lab
- JSON
- JSON (JavaScript Object Notation) is a text format for writing structured data as characters so that it can be exchanged (RFC 8259 section 1). An object is written inside { } as "name": value pairs joined by commas, and an array is written inside [ ] as values joined by commas. A name must always be a string wrapped in double quotes (section 4), and a comma goes only between values (the grammar in sections 4 and 5). It is widely used where programs exchange data, such as when a server sends data to a browser, and when the receiving side gets text that breaks these rules, it usually cannot read the whole text.
- JSON values
- A JSON value is one of an object, an array, a number, a string, or one of the three words false, null, and true (RFC 8259 section 3). A string is wrapped in double quotes (section 7), a number is written as decimal digits without quotes (section 6), and false, null, and true are written in lowercase without quotes (section 3). Whether there are quotes decides the kind of the value, so 30 is a number and "30" is a string. Calculations after reading follow the kind too: in JavaScript, 30 plus 1 is 31, but the string "30" plus 1 becomes the string "301".
- Parsing
- Parsing is reading data written as characters from the start according to a grammar and turning it into a structure (such as an object) that a program can work with, and the program that does it is called a parser. RFC 8259 section 9 says that a JSON parser transforms a JSON text into another representation, and that it must accept all texts that conform to the JSON grammar. When a parser meets text that breaks the grammar, it raises an error. The same section also says that a parser may accept forms or extensions other than JSON, so some parsers can be set to accept things such as single quotes or a trailing comma.
- Serialization and deserialization
- Serialization converts an object into a form that can be stored or sent (such as a sequence of bytes or JSON), and deserialization restores an object from that form. In web APIs, the typical case is conversion between objects and JSON (for example with Jackson). Java's built-in serialization (Serializable) has compatibility problems when the class structure changes and carries security risks, so formats such as JSON are mostly used today.
Try these
- Default settings — JSON text that follows the rules. The parser reads it and creates an object whose age is a number.
- Putting double quotes around 30 — It is read, but age becomes a string, so adding 1 gives 301.
- Removing the double quotes around the name — The name has no quotes, so the whole text cannot be read.
- Using single quotes — A single quote is not a JSON quote, so the whole text cannot be read.
- Adding a comma after the last value — A name must follow the comma, but the end (}) comes, so the whole text cannot be read.
- Leaving out a comma — There is no comma between the values, so the whole text cannot be read.
Running with the default settings
- The server wants to send member information to the browser. The object in the server's memory (the one with a name, an age, and tags) cannot be sent as it is. So it is written out as text by an agreed set of rules, and those rules are JSON. The sender wrote the object as the text below. The parser on the receiving side reads this text and turns it back into an object. This lab fed the same text to two parsers, JSON.parse in Node.js and Jackson in Java, and in every combination both parsers made the same decision.
- The parser on the receiving side reads the text from the start, one character after another. The first character is {. A { means "an object of names and values starts here," so the parser now expects "name": value pairs joined by commas and ending with }.
- Next comes "name". Inside the object, a string wrapped in double quotes is a name. The : after it marks "what follows is the value of this name."
- The "Alice" after the : is wrapped in double quotes, so it is a string value. A comma follows, so another "name": value pair comes next.
- This is the line after the comma. "age" is a name wrapped in double quotes, and the value after the : is 30. It has no double quotes and looks like a number, so it is a number value. A comma follows, so the next pair comes next.
- This is the line after the comma. "tags" is a name wrapped in double quotes, and its value starts with [. [ ] is an array of several values. The "vip" and "new" inside are both wrapped in double quotes, so they are two strings, separated by the comma between them. The array ends at ].
- Finally the parser meets }. It comes with no comma before it, so the object that started with { ends here. The parser read all the way to the end without a single rule violation.
- The read succeeded, and the receiving side created an object in its own language. name is the string "Alice", age is the number 30, and tags is an array of two strings. The text that was sent as characters became an object again.
- The receiving program takes age from the object it read and adds 1 (this is the result of running age + 1 in JavaScript on the object that was read). age is the number 30, so this adds numbers, and the result is 31.
Result of this run
- JSON is an agreed way to write an object as text so it can be sent. Inside { }, write "name": value pairs joined by commas, wrap names and string values in double quotes, and write numbers without quotes. The parser on the receiving side read this text from the start and made an object.
- The 30 in age has no quotes, so it is a number, and adding 1 gives 31. The text was read because it did not break the rules anywhere.
Code
{
"name": "Alice",
"age": 30,
"tags": ["vip", "new"]
}
Assumptions of this model
We used two parsers. One is JSON.parse in Node.js 24.18.0 (the standard JavaScript parser). The other is Jackson 3.1.5 (jackson-databind and jackson-core) run on Java 21.0.12.1 with the default settings, that is, readTree of the parser made with JsonMapper.builder().build(). For all eighteen combinations, we fed the same characters as the code box (lines end with \n, with no line break at the end) to both parsers as they are, and checked against the model: success or failure, the line, column, and character at the position of the error, the kind of age that was read (typeof for JSON.parse, the node kind for Jackson), and the names and values that were read. The two parsers made the same success or failure decision in all eighteen combinations, and when it failed, the error position was the same too. When it failed, both parsers only raised an error and did not return the part they had read, and when the text had more than one error, they reported only the first one they met. The original error messages differ between the two (for example, JSON.parse says "Expected property name or '}' in JSON at position 4" and Jackson says "was expecting double-quote to start property name"), and the screen shows only the kind of error, written in English. The original messages are in the Probe output. The "age + 1 on the object that was read (JavaScript)" on the screen is JavaScript behavior. It is the value of adding 1 to age of the object read with JSON.parse (we also checked typeof: the number 30 gives the number 31, and the string "30" gives the string "301"), and it is not Java behavior. When the same text is read with Jackson, age is a string node, and the intValue() of that node raised an error (JsonNodeException), while asInt() and reading into a record with an integer field both gave 30. That is Jackson's conversion behavior, so it is not used on the screen. Some parsers have options to accept text that breaks the rules, depending on the settings. What we checked is only this: turning on three Jackson JsonReadFeature options (ALLOW_SINGLE_QUOTES, ALLOW_UNQUOTED_PROPERTY_NAMES, ALLOW_TRAILING_COMMA) makes a name wrapped in single quotes, a name without quotes, and a comma after the last value readable (text with a missing comma was still not readable). All the checks on the screen were made with the default settings. We did not look at other parsers or at the settings of JSON.parse. Text with a comment in it was also not readable by either parser with the default settings. What we checked against the documentation is RFC 8259 section 1 (JSON is a text format for the serialization of structured data), section 2 (grammar; whitespace around the structural characters has no meaning), section 3 (a value is an object, array, number, or string, or false, null, or true, and these words are lowercase), section 4 (grammar of objects: members joined by commas, and a name is a string), section 5 (grammar of arrays), section 6 (numbers are written as decimal digits), section 7 (a string begins and ends with quotation marks, and the only quotation mark is the double quote, %x22), and section 9 (a parser must accept all texts that conform to the grammar, and may accept forms other than JSON). The documents were opened only as summaries, so we could not check them against the full original text. The statement that a trailing comma and single quotes are not allowed is not written directly in the document. We based it on the fact that the grammar in sections 4 and 5 has no shape with nothing after a comma and no single-quote shape, together with the run results above. The JSON on the screen covers only the object, array, string, and number among the kinds of values, and does not cover true, false, null, nested objects, or escapes inside strings (such as \n). The in-depth lab on the same subject (how a server converts between objects and JSON) is "REST APIs and message converters".
Previous lab: Cookies · Next lab: HTTPS