JSON
05 / 06

JSON Syntax, Data Types & APIs

JSON: Syntax, Data Types & APIs

JSON (JavaScript Object Notation) is a lightweight text format for data interchange. It's language-independent, human-readable, and the dominant format for REST APIs, config files, and NoSQL databases.

Valid JSON Types

{
  "string": "text value",
  "number": 42,
  "float": 3.14,
  "negative": -7,
  "scientific": 1.5e10,
  "boolean_true": true,
  "boolean_false": false,
  "null_value": null,
  "array": [1, "two", true, null, {"nested": "object"}],
  "object": {
    "nested": "values",
    "deeper": { "a": 1 }
  }
}

Common Gotchas

  • No trailing commas — {"a":1,} is invalid (unlike JavaScript objects)

  • No comments — // and /* */ are not valid JSON (use JSONC for config files with comments)

  • Keys must be double-quoted strings — {a: 1} is invalid

  • Strings must use double quotes — single quotes are invalid

  • Numbers: no leading zeros (010 is invalid), no NaN/Infinity (not valid JSON)

  • No undefined — only null for missing values

  • Integer precision: JavaScript loses precision for integers > 2^53. Use strings for large IDs.

JSON.parse & JSON.stringify

// Basic parse/stringify
const obj = JSON.parse('{"name":"Alice","age":30}');
const json = JSON.stringify({ name: 'Alice', age: 30 });

// Pretty-print with indent
const pretty = JSON.stringify(data, null, 2);

// Replacer function — filter/transform during stringify
const filtered = JSON.stringify(user, (key, value) => {
  if (key === 'password' || key === 'ssn') return undefined; // exclude sensitive
  if (value instanceof Date) return value.toISOString();
  return value;
}, 2);

// Array replacer — include only listed keys
JSON.stringify(user, ['name', 'email'], 2);

// Reviver function — transform during parse
const parsed = JSON.parse(jsonString, (key, value) => {
  if (key === 'createdAt') return new Date(value);  // string → Date
  if (key === 'price') return parseFloat(value);    // string → number
  return value;
});

// Handle errors
try {
  const data = JSON.parse(maybeInvalidJson);
} catch (err) {
  console.error('Invalid JSON:', err.message);
  // SyntaxError: Unexpected token ...
}

Working with APIs (Fetch)

// GET request
const response = await fetch('https://api.example.com/users/1');
if (!response.ok) throw new Error(`HTTP ${response.status}: ${response.statusText}`);
const user = await response.json();  // Parses JSON body

// POST with JSON body
const created = await fetch('https://api.example.com/users', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${token}`,
  },
  body: JSON.stringify({ name: 'Alice', email: 'alice@example.com' }),
});
const newUser = await created.json();

// Handle errors properly
async function apiRequest(url, options = {}) {
  const res = await fetch(url, {
    headers: { 'Content-Type': 'application/json' },
    ...options,
    body: options.body ? JSON.stringify(options.body) : undefined,
  });

  if (!res.ok) {
    const error = await res.json().catch(() => ({ message: res.statusText }));
    throw Object.assign(new Error(error.message), { status: res.status });
  }
  if (res.status === 204) return null;  // No content
  return res.json();
}

JSON in Node.js

import { readFileSync, writeFileSync } from 'fs';
import { readFile, writeFile } from 'fs/promises';

// Read JSON file synchronously
const config = JSON.parse(readFileSync('./config.json', 'utf8'));

// Read JSON file asynchronously
const data = JSON.parse(await readFile('./data.json', 'utf8'));

// Write JSON file
await writeFile('./output.json', JSON.stringify(result, null, 2) + '
');

// Deep clone via JSON (loses functions, Dates, undefined, Sets, Maps)
const clone = JSON.parse(JSON.stringify(original));
// Prefer structuredClone() in modern Node.js for proper deep clone

JSONL (Newline-Delimited JSON)

JSONL (JSON Lines) stores one JSON object per line. Used for log files, streaming APIs, and large datasets where you process records one at a time without loading everything into memory.

// Read JSONL file line by line
import { createReadStream } from 'fs';
import { createInterface } from 'readline';

const rl = createInterface({
  input: createReadStream('data.jsonl'),
  crlfDelay: Infinity,
});

for await (const line of rl) {
  if (line.trim()) {
    const record = JSON.parse(line);
    await processRecord(record);
  }
}

// Write JSONL
const stream = createWriteStream('output.jsonl');
for (const item of items) {
  stream.write(JSON.stringify(item) + '
');
}
stream.end();

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free