JSON Cheatsheet - Syntax, Data Types & Parsing Examples
In frontend-backend integration, JSON is the default format for API responses and one of the easiest to break with a trailing comma or an unquoted key. This reference covers 6 high-frequency groups — data types, objects, arrays, nesting, common API response patterns, and validation/formatting commands (JSON.parse, jq). It helps you write well-formed data from a template and gives you a checklist for debugging plus jq for quick validation. After reading you can assemble valid JSON and verify it with tooling quickly.
Typical Use Case
In API integration and frontend-backend handoff, JSON is the default exchange format, with three recurring scenarios: building a request payload, reading nested fields from a response, and troubleshooting why JSON.parse throws. When the API returns a paginated data.items array plus a total, you follow the comma patterns to read the fields; when building a request you must keep every key double-quoted with no trailing comma. A quick jsonlint or jq check afterwards cuts down a lot of back-and-forth during integration. After reading this table you can write well-formed JSON and validate it with tooling yourself.
Data Types 6
"string"123 / -456 / 3.14true / falsenull{"key": "value"}[1, 2, 3]Object 5
{"name": "tom"}{"name": "tom", "age": 20}{"user": {"name": "tom"}}{"users": [{"name": "tom"}]}{"key with space": "value"}Array 5
[1, 2, 3]["a", "b", "c"][{"id": 1}, {"id": 2}][[1, 2], [3, 4]][1, "text", true, null]Nested 3
{"user": {"name": "tom", "age": 20}}{"users": [{"name": "tom"}, {"name": "jerry"}]}[{"id": 1, "tags": ["a", "b"]}]Common Patterns 4
{"code": 200, "message": "success"}{"error": {"code": 404, "message": "Not found"}}{"data": {"items": [], "total": 100}}{"id": 1, "created_at": "2026-07-19T10:30:00Z"}Validation 5
JSON.parse(str)JSON.stringify(obj)JSON.stringify(obj, null, 2)jsonlint file.jsonjq . file.jsonParameter matrix
| Parameter | Effect | Example |
|---|---|---|
"string" | A string value; both keys and values are double quoted, and it is the most common type in JSON | {"name": "tom"} |
123 / -456 / 3.14 | Numbers, integers and decimals written without quotes; they cannot carry exact values such as money | {"age": 20} |
true / false | Booleans, lowercase only, with no standing in for 1 and 0 | {"ok": true} |
null | An explicit null, which is a different state from the key being absent | {"deleted_at": null} |
{"key": "value"} | An object, a set of key-value pairs; what happens to a repeated key is parser-defined | {"key with space": "value"} |
[1, 2, 3] | An array, an ordered list whose element types may differ, indexed from 0 | ["a", "b", "c"] |
{ } | An object inside an object, expressing hierarchy and requiring stepwise access | {"user": {"name": "tom"}} |
[{ }] | An array of objects, the standard shape for a list in an API response | {"users": [{"name": "tom"}, {"name": "jerry"}]} |
[[ ]] | An array of arrays, which maps directly onto table rows and columns | [[1, 2], [3, 4]] |
[mixed] | An array like [1, "text", true, null] parses fine, but consumers must branch on type before use | [1, "text", true, null] |
{ code, message, data } | The business code and message live in the body, a layer separate from the HTTP status | {"code": 200, "message": "success"} |
{ error: { code, message } } | Nested under an error key so failures still have a fixed parseable shape | {"error": {"code": 404, "message": "Not found"}} |
{ items, total } | items holds the current page and total the record count, split so the client can compute pages | {"data": {"items": [], "total": 100}} |
"2026-01-01T00:00:00Z" | Always ISO 8601 with a trailing Z, so no two ends invent different formatting | {"id": 1, "created_at": "2026-07-19T10:30:00Z"} |
JSON.parse(str) | Parse a JSON string into a value; malformed input throws rather than returning a half-built result | |
JSON.stringify(obj) | Serialise a value back to a JSON string, with key order normalised in the output | |
JSON.stringify(obj, null, 2) | The same serialisation with two-space indentation, readable and diff-friendly | |
jsonlint file.json | Validate the syntax from the command line and print the offending position | jsonlint file.json |
jq . file.json | Pretty-print and query from the command line, doubling as a syntax check | jq . file.json |
Common pitfalls
SymptomThe endpoint returned data but the client treats it as a failure.
CauseThe business code sits in the body, as in {"code": 200, "message": "success"}, and a truthiness check on the whole object ignores the code layer entirely.
FixRead the code at the agreed path such as data.code before deciding, rather than inferring success from truthiness.
SymptomA large integer ID arrives at the backend with trailing zeros.
CauseWritten as a JSON number it exceeds the exactly representable double range, so low digits are flattened during parsing; snowflake IDs and long order numbers both hit this.
FixAlways pass IDs as strings and keep them strings through every hop instead of converting to a number in between.
SymptomAn amount is off by a tiny fraction and the books do not balance.
CauseA decimal written as a JSON number is stored as binary floating point, where values such as 12.34 have no exact representation, and the error survives a serialize-parse round trip.
FixCarry money as an integer in the smallest unit or as a string, converting to a decimal only at the display layer.
SymptomAfter merging objects from two sources a field is simply gone.
CauseThe same key appears twice in one object, and parsers differ between last-wins and first-wins, so the outcome varies and nothing is reported.
FixAssert that critical keys stay unique after merging, and prefix keys with their origin when collisions are possible.
SymptomA file that parses fine locally fails with an illegal escape on another machine.
CauseA backslash in the path is read as the start of an escape sequence, and backslashes must appear in pairs; splicing a Windows path straight into JSON hits exactly that.
FixLet JSON.stringify handle escaping during serialisation instead of hand-assembling JSON strings containing paths.
SymptomChinese text in the payload turns into question marks or blocks and emoji vanish entirely.
CauseOne end read or wrote the bytes without UTF-8, decoding them as a single-byte encoding so the sequences no longer map back to characters.
FixDeclare UTF-8 explicitly on both ends and add the charset parameter to the Content-Type header.
SymptomParsing succeeds but the field I reach for is undefined.
CauseThe array-of-objects level is easy to miss by one index: for {"users": [{"name": "tom"}]} you step into users first and only then into each element.
FixPrint the shape with jq . file.json to confirm the levels, then write the access path.
SymptomParsing fails but the message does not say which line is wrong.
CauseThe error usually reports a character offset without a reason, while the real fault is often a local one: a trailing comma, a comment, or an unquoted key.
FixValidate the file on its own with jsonlint file.json, then inspect the reported position and the text around it.
SymptomThe same data yields a different key order on each side, so every diff is noise.
CauseObjects are unordered and serialisation reorders keys, so an order that carries no meaning pollutes version control diffs.
FixCompare structure rather than text: normalise both sides with jq . file.json before diffing.
Troubleshooting
1Validate the syntax first and pin the offending position
jsonlint file.jsonNo output means the syntax is fine; with output, the reported position is the first error, so fix it and rerun before anything else.
2Pretty-print the file to check its structural levels
jq . file.jsonA valid file comes back re-indented; an invalid one errors right here, which doubles as a check.
3Pull the total out of the paginated shape to confirm the path works
jq '.data.total' file.jsonThis matches the {"data": {"items": [], "total": 100}} shape; a null result means the path does not line up with the real structure, so print the structure first.
4Reproduce the parse failure in Node to get a positioned error
node -e 'JSON.parse(require("fs").readFileSync("file.json","utf8"));console.log("ok")'A printed ok means it parsed; when it throws, the error carries a character position, which localizes the fault far better than a bare syntax complaint.
5Confirm that the serialiser really applies indentation
node -e 'const o={user:{name:"tom",age:20}};console.log(JSON.stringify(o,null,2))'The two-space output is what you read and diff; if it collapses to one line, the indent argument is in the wrong position.
Command Examples
Pretty-print for readability and meaningful diffs
JSON.stringify(obj, null, 2)Minified JSON turns any edit into a full-line change, so reviews show nothing useful. Pretty-printing with the third argument of JSON.stringify makes a one-field change a one-line diff.
Output
{
"name": "tom",
"tags": [
"a",
"b"
]
}Extract just the fields you need with jq and sanity-check the shape
jq '[.users[] | {id, name}]' data.json.users[] walks the array and projects each element, shrinking the payload dramatically. jq emits null for missing fields rather than failing, which makes it a quick way to confirm an API response nests where you expect it to.
Output
[
{
"id": 1,
"name": "tom"
},
{
"id": 2,
"name": "jerry"
}
]Gate the syntax with jsonlint before committing
jsonlint data.jsonTrailing commas, single quotes and raw newlines are hard to spot by eye and surface as a vague "Unexpected token". Running jsonlint before commit or ingest removes an entire debugging round trip.
Output
data.json: Invalid JSON:
1:14: trailing comma
$ jsonlint data.json
Error: Invalid JSON
line 1 column 14
trailing commaWrite timestamps as RFC 3339 with an explicit Z
{ "id": 1, "created_at": "2026-07-19T10:30:00Z" }A timestamp without a zone gets read in the client local time, so day boundaries and billing totals stop matching. A Z or an explicit +08:00 offset makes parsing unambiguous and keeps cross-timezone aggregation correct.
Common Pitfalls
- JSON allows neither comments nor trailing commas: a helpful // comment or a comma after the last member makes the document unparseable, and many parsers report only a position with no reason.
- Illegal escape sequences such as
"a\b"break strict parsers: a backslash must be doubled, so Windows paths embedded directly in JSON are a reliable source of failures. - JSON numbers are IEEE doubles, so an amount stored as 12.34 comes back as 12.339999999999999. Never use JSON floats for money; use integer minor units or a string.
- Duplicate keys behave inconsistently across parsers (last wins, or first wins), so objects merged from several sources can silently drop fields. Assert key uniqueness after merging.
- Integers beyond 2^53 lose precision, so a snowflake ID or long order number sent as a JSON number can come back with its trailing digits zeroed. Send such IDs as strings.
- Non-ASCII text decoded as anything other than UTF-8 turns into mojibake, and once corrupted data is persisted the original content is usually unrecoverable.
Tips
- JSON keys must use double quotes — single quotes or unquoted keys are invalid.
- JSON does not support comments. Use JSONC (JSON with Comments) if comments are needed.
- Use ISO 8601 format for date/time (e.g., "2026-07-19T10:30:00Z").
FAQ
How do I represent a newline inside a JSON string?
Literal newline characters are not allowed inside JSON strings; they must be escaped as \n (and tabs as \t). Using JSON.stringify(value) does this automatically. Chinese characters can stay as-is in UTF-8 and usually need no escaping.
What causes most JSON errors and how do I locate them fast?
The three usual suspects are missing double quotes on keys, a trailing comma at the end of an object or array, and unbalanced braces or quotes. Validate with jq . to get the line and error type; in the browser wrap JSON.parse in try/catch and log the failing fragment, then narrow it by bisecting.
Do I need to escape Chinese characters in JSON?
Not required by the spec — Chinese written directly as UTF-8 is valid and parsed fine by most tools. Only if a channel insists on ASCII (legacy headers or log pipelines) should you convert to \uXXXX escapes, e.g. via the -ascii option or equivalent tooling.
Is writing JSON numbers as quoted strings a problem?
It parses fine but changes semantics: "123" is a string while 123 is a number, affecting typeof, math and lexicographic sorting. Use strings for very long IDs or values with leading zeros; otherwise write numbers literally, and use true/false rather than the strings true or false.
How do I quickly validate nested or large JSON and extract values?
jq is the handiest: jq . file.json validates and pretty-prints, jq '.key' reads a value, jq 'length' returns an array length, and jq empty file.json only checks validity. In the browser wrap JSON.parse in try/catch; for a visual sandbox use jqplay or an online formatter and validator.
Official References
Each command links to its official documentation below, so you can verify the latest usage and read deeper.
Maintained by LaoHand
Publicly updated on Jul 21, 2026, continuously proofread against official docs.
Contact Us
Wrong command or description? Send us corrections, business inquiries or product feedback by email.
Contact Us