JSON Schema, Validation & Tooling JSON Schema Basics JSON Schema is a vocabulary for annotating and validating JSON. Used in API contracts (OpenAPI), config val…
JSON Schema, Validation & Tooling
JSON Schema Basics
JSON Schema is a vocabulary for annotating and validating JSON. Used in API contracts (OpenAPI), config validation, form validation, and IDE autocomplete.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/user.schema.json",
"title": "User",
"type": "object",
"required": ["id", "name", "email"],
"additionalProperties": false,
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"name": {
"type": "string",
"minLength": 2,
"maxLength": 100
},
"email": {
"type": "string",
"format": "email"
},
"role": {
"type": "string",
"enum": ["admin", "user", "guest"]
},
"age": {
"type": "integer",
"minimum": 0,
"maximum": 150
},
"tags": {
"type": "array",
"items": { "type": "string" },
"uniqueItems": true
},
"address": {
"$ref": "#/$defs/Address"
}
},
"$defs": {
"Address": {
"type": "object",
"required": ["street", "city"],
"properties": {
"street": { "type": "string" },
"city": { "type": "string" },
"zip": { "type": "string", "pattern": "^[0-9]{5}$" }
}
}
}
}
Validation with Zod (TypeScript)
import { z } from 'zod';
const UserSchema = z.object({
id: z.number().int().positive(),
name: z.string().min(2).max(100),
email: z.string().email(),
role: z.enum(['admin', 'user', 'guest']).default('user'),
age: z.number().int().min(0).max(150).optional(),
tags: z.array(z.string()).default([]),
createdAt: z.string().datetime().transform(s => new Date(s)),
});
type User = z.infer<typeof UserSchema>;
// Parse (throws on invalid)
const user = UserSchema.parse(rawData);
// Safe parse (returns result object, never throws)
const result = UserSchema.safeParse(rawData);
if (result.success) {
console.log(result.data);
} else {
console.error(result.error.format());
// { name: { _errors: ['String must contain at least 2 character(s)'] } }
}
// Validate API request body in Next.js
export async function POST(req: Request) {
const body = await req.json();
const parsed = UserSchema.safeParse(body);
if (!parsed.success) {
return Response.json({ errors: parsed.error.format() }, { status: 400 });
}
return Response.json(await createUser(parsed.data));
}
jq — Command-Line JSON Processor
# Pretty print
cat data.json | jq .
curl -s api.example.com/users | jq .
# Extract field
jq '.name' data.json
jq '.users[0].email' data.json
# Filter array
jq '.users[] | select(.age > 18)' data.json
jq '.users[] | select(.role == "admin") | .name' data.json
# Transform: build new object
jq '.users[] | {id, name, isAdmin: (.role == "admin")}' data.json
# Get array of values
jq '[.users[].name]' data.json
jq '[.users[] | select(.active)] | length' data.json
# Modify values
jq '.users[] | .name = (.name | ascii_upcase)' data.json
# Combine files
jq -s '.[0] * .[1]' base.json override.json # merge
# Output as TSV
jq -r '.users[] | [.id, .name, .email] | @tsv' data.json
# Process API responses
curl -s "https://api.github.com/repos/vercel/next.js" | \
jq '{name, stars: .stargazers_count, forks: .forks_count, language}'
JSON Patch (RFC 6902)
JSON Patch describes changes to a JSON document as an array of operations. Used in REST APIs for partial updates (PATCH method).
[
{ "op": "add", "path": "/tags/-", "value": "typescript" },
{ "op": "remove", "path": "/deprecated" },
{ "op": "replace", "path": "/name", "value": "New Name" },
{ "op": "move", "from": "/author/name", "path": "/authorName"},
{ "op": "copy", "from": "/template", "path": "/instance" },
{ "op": "test", "path": "/version", "value": "2.0" }
]
JSON5 & JSONC
JSON5: superset of JSON allowing comments, trailing commas, single quotes, unquoted keys, multiline strings. Used in some config files.
JSONC (JSON with Comments): VS Code's format for settings.json, tsconfig.json. Comments allowed, trailing commas sometimes.
tsconfig.json, .eslintrc.json use JSONC — VS Code handles them with special parser.
For programmatic use, parse JSONC with json5 or strip-json-comments npm packages.
JSON in Databases
PostgreSQL: json (stored as text, validated) vs jsonb (binary, indexable, operators). Prefer jsonb.
PostgreSQL jsonb operators: -> (get key), ->> (get key as text), #> (path), @> (contains), ? (key exists)
MySQL: JSON type with JSON_EXTRACT(), JSON_SET(), JSON_CONTAINS(). Path: $.key.nested
MongoDB: native BSON (superset of JSON). Query nested: {"address.city": "Kyiv"}
SQLite: JSON1 extension with json_extract(), json_object(), json_array()