Chapters: JavaScript HTML & CSS JSON XML YAML ← Full TOC

📊 Chapter 32 — JSON

Complete reference for JSON — syntax, JavaScript, Python, jq command-line tools, JSON Schema validation, and REST API patterns with copy-paste examples.
Part of The Direct Path to Linux Ubuntu — free for all.

4Topics
85+Concepts
5Examples
jsonFormat
RFC 8259Standard
FreeNo login
📋 JSON Syntax ⚡ JSON in JavaScript 🐍 JSON in Python 🔧 Tools & Schema ⚡ Examples

📋 JSON Syntax

📋 JSON SyntaxData types, syntax rules, and valid JSON structure

⚡ JSON in JavaScript

⚡ JSON in JavaScriptJSON.parse, JSON.stringify, fetch, and manipulation

🐍 JSON in Python

🐍 JSON in Pythonjson module — loads, dumps, load, dump

🔧 Tools & Schema

🔧 JSON Tools & Schemajq, JSON Schema, JSON Pointer, and REST API patterns

⚡ Quick Examples

JSON works in every language. Run Python examples with python3 script.py.

JSON Syntax Cheatsheet

All valid JSON data types and structures.

{
  "types_demo": {
    "string":   "Hello, World!",
    "number_int": 42,
    "number_float": 3.14159,
    "number_sci": 1.5e10,
    "number_neg": -273.15,
    "boolean_t": true,
    "boolean_f": false,
    "null_val":  null,
    "array":    [1, "two", true, null, [3, 4], {"nested": "object"}],
    "object":   {"key": "value", "num": 99}
  },
  "real_world_api_response": {
    "status":  "success",
    "code":    200,
    "data": {
      "users": [
        {"id": 1, "name": "Alice",  "role": "admin",  "active": true},
        {"id": 2, "name": "Bob",    "role": "user",   "active": true},
        {"id": 3, "name": "Carol",  "role": "user",   "active": false}
      ],
      "total": 3,
      "page":  1,
      "per_page": 10
    },
    "timestamp": "2026-06-25T12:00:00Z"
  },
  "INVALID_examples_dont_copy": {
    "comment": "// This is NOT valid JSON — no comments allowed",
    "single_quotes": "Use double quotes only",
    "trailing_comma_bad": "Remove trailing commas",
    "undefined_bad": "undefined is not a JSON type",
    "nan_bad": "NaN is not valid JSON — use null",
    "inf_bad": "Infinity is not valid JSON — use null"
  }
}

Parse and Validate JSON (Python)

Safe JSON parsing with schema validation.

import json
from typing import Any

def safe_json_parse(text: str, default: Any = None) -> Any:
    try:
        return json.loads(text)
    except json.JSONDecodeError as e:
        print(f"JSON parse error at line {e.lineno}, col {e.colno}: {e.msg}")
        return default

def validate_student(data: dict) -> list[str]:
    errors = []
    if not isinstance(data.get('name'), str) or not data['name']:
        errors.append("name must be non-empty string")
    if not isinstance(data.get('score'), (int, float)) or not 0 <= data['score'] <= 100:
        errors.append("score must be number 0-100")
    if not isinstance(data.get('email'), str) or '@' not in data.get('email',''):
        errors.append("email must be valid email address")
    return errors

# Test cases
tests = [
    '{"name":"Alice","score":95,"email":"alice@example.com"}',
    '{"name":"","score":110,"email":"notanemail"}',
    '{"name":"Carol","score":92,"email":"carol@test.com","extra":"ok"}',
    'not valid json',
    '{"name":null}',
]

for t in tests:
    obj = safe_json_parse(t)
    if obj is None: continue
    errors = validate_student(obj)
    if errors:
        print(f"❌ {obj.get('name','?')}: {'; '.join(errors)}")
    else:
        print(f"✅ {obj['name']} (score={obj['score']})")

# Round-trip fidelity check
original = {"name": "Alice", "scores": [95,87,92], "info": {"active": True, "grade": None}}
restored = json.loads(json.dumps(original))
assert original == restored, "Round-trip failed!"
print("Round-trip: ✅ identical")
# python3 validate.py

JSON API Client (Python)

Fetch, post, and process JSON REST APIs.

import json, urllib.request, urllib.error
from typing import Optional

BASE = "https://jsonplaceholder.typicode.com"

def api_get(path: str) -> Optional[dict]:
    try:
        with urllib.request.urlopen(f"{BASE}{path}") as resp:
            return json.loads(resp.read().decode())
    except urllib.error.URLError as e:
        print(f"GET {path} failed: {e}")
        return None

def api_post(path: str, data: dict) -> Optional[dict]:
    try:
        req = urllib.request.Request(
            f"{BASE}{path}",
            data=json.dumps(data).encode(),
            headers={"Content-Type": "application/json"},
            method="POST"
        )
        with urllib.request.urlopen(req) as resp:
            return json.loads(resp.read().decode())
    except urllib.error.URLError as e:
        print(f"POST {path} failed: {e}")
        return None

# GET individual post
post = api_get("/posts/1")
if post:
    print(f"Post #{post['id']}: {post['title'][:50]}")

# GET posts and filter
posts = api_get("/posts")
if posts:
    user1_posts = [p for p in posts if p["userId"] == 1]
    print(f"User 1 has {len(user1_posts)} posts")
    avg_words = sum(len(p["body"].split()) for p in user1_posts) / len(user1_posts)
    print(f"Average body words: {avg_words:.1f}")

# POST new resource
new_post = api_post("/posts", {
    "title": "MyWebUniversity JSON Tutorial",
    "body":  "JSON is the universal data format",
    "userId": 1
})
if new_post:
    print(f"Created post id: {new_post['id']}")
    print(json.dumps(new_post, indent=2))
# python3 api_client.py

jq One-Liners Reference

Essential jq commands for JSON processing.

# jq — the essential command-line JSON processor
# Install: sudo apt install jq  /  brew install jq  /  winget install jqlang.jq

# ── Basic extraction ─────────────────────────────────────────
jq '.'                              file.json   # pretty-print
jq '.name'                          file.json   # extract field
jq '.user.address.city'             file.json   # nested field
jq '.items[0]'                      file.json   # first array element
jq '.items[-1]'                     file.json   # last array element
jq '.items[1:3]'                    file.json   # slice
jq '.items | length'                file.json   # array length
jq 'keys'                           file.json   # object keys
jq 'values'                         file.json   # object values
jq 'has("name")'                    file.json   # check key exists
jq 'type'                           file.json   # value type

# ── Array operations ─────────────────────────────────────────
jq '.[]'                            file.json   # iterate array
jq '[.[].name]'                     file.json   # extract field from all
jq '[.[] | select(.score > 90)]'    file.json   # filter
jq '[.[] | select(.active == true)]' file.json  # filter boolean
jq 'sort_by(.score)'                file.json   # sort ascending
jq 'sort_by(.score) | reverse'      file.json   # sort descending
jq 'unique_by(.subject)'            file.json   # deduplicate
jq 'group_by(.subject)'             file.json   # group
jq 'map(.score) | add'              file.json   # sum
jq '(map(.score) | add) / length'   file.json   # average
jq 'map(select(.score >= 90)) | length' file.json  # count matching

# ── Transformation ───────────────────────────────────────────
jq '[.[] | {name, score}]'          file.json   # pick fields
jq '[.[] | .name + ": " + (.score|tostring)]' file.json  # string join
jq '[.[] | {(.name): .score}] | add' file.json  # to object
jq '.[] |= . + {"rank": "A"}'       file.json   # add field to all

# ── Conditional ──────────────────────────────────────────────
jq '[.[] | if .score >= 90 then . + {grade:"A"} else . + {grade:"B"} end]' file.json

# ── With variables ───────────────────────────────────────────
jq --arg name "Alice" '.[] | select(.name == $name)' file.json
jq --argjson min 90  '.[] | select(.score >= $min)'  file.json

# ── Compact + raw output ─────────────────────────────────────
jq -c '.'          file.json   # compact (no whitespace)
jq -r '.name'      file.json   # raw (no quotes)
jq -r '.[].name'   file.json   # one name per line (for shell loops)

# ── Pipe from curl ───────────────────────────────────────────
curl -s https://jsonplaceholder.typicode.com/posts/1 | jq '.'
curl -s https://jsonplaceholder.typicode.com/posts | jq 'length'
curl -s https://api.github.com/repos/torvalds/linux | jq '{name,stars:.stargazers_count}'

JSON Schema Validation

Define and validate JSON structure with JSON Schema.

# JSON Schema — validate data structure
# pip install jsonschema

import json
import jsonschema
from jsonschema import validate, ValidationError, Draft202012Validator

# ── Define schema ─────────────────────────────────────────────
STUDENT_SCHEMA = {
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://mywebuniversity.com/schemas/student.json",
  "title": "Student",
  "description": "A student enrollment record",
  "type": "object",
  "required": ["name", "email", "score", "subject"],
  "properties": {
    "id":      {"type": "integer", "minimum": 1},
    "name":    {"type": "string",  "minLength": 1, "maxLength": 100},
    "email":   {"type": "string",  "format": "email",
                "pattern": "^[\\w.+-]+@[\\w-]+\\.[\\w.]+$"},
    "score":   {"type": "number",  "minimum": 0, "maximum": 100},
    "subject": {"type": "string",
                "enum": ["Math", "Science", "English", "History", "CS"]},
    "grade":   {"type": "string",  "pattern": "^[A-F][+-]?$"},
    "active":  {"type": "boolean"},
    "tags":    {"type": "array",   "items": {"type": "string"}, "uniqueItems": True},
    "metadata":{"type": "object",
                "properties": {"created": {"type": "string", "format": "date"}}},
  },
  "additionalProperties": False
}

# ── Test data ─────────────────────────────────────────────────
test_cases = [
  {"name": "Alice",  "email": "a@test.com", "score": 95.0, "subject": "CS",
   "grade": "A+", "active": True, "tags": ["dean-list"]},
  {"name": "",       "email": "not-email",  "score": 110,  "subject": "Arts"},  # multiple errors
  {"name": "Carol",  "email": "c@test.com", "score": 92,   "subject": "Math",
   "unknown_field": "not allowed"},
]

validator = Draft202012Validator(STUDENT_SCHEMA)
for i, data in enumerate(test_cases, 1):
  errors = list(validator.iter_errors(data))
  if not errors:
    print(f"  ✅ Case {i} — Valid: {data['name']}")
  else:
    print(f"  ❌ Case {i} — {len(errors)} error(s):")
    for e in sorted(errors, key=lambda e: e.path):
      path = ' > '.join(str(p) for p in e.path) or 'root'
      print(f"     [{path}] {e.message}")

# ── Generate schema from data (schema inference) ──────────────
def infer_type(val):
  if val is None:     return "null"
  if isinstance(val, bool): return "boolean"
  if isinstance(val, int):  return "integer"
  if isinstance(val, float):return "number"
  if isinstance(val, str):  return "string"
  if isinstance(val, list): return "array"
  if isinstance(val, dict): return "object"

sample = {"name":"Alice","score":95,"active":True,"courses":["Math","CS"]}
inferred = {"type":"object","properties":{k:{"type":infer_type(v)} for k,v in sample.items()}}
print("\nInferred schema:")
print(json.dumps(inferred, indent=2))
# python3 schema_demo.py