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.
JSON works in every language. Run Python examples with python3 script.py.
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"
}
}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.pyFetch, 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.pyEssential 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}'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