The Complete Guide to JSON Formatting for API Development
If you work with APIs, you work with JSON. That's just the reality of modern web development. And yet, I see developers — senior ones — waste an embarrassing amount of time on JSON formatting issues that should take seconds to fix.
This isn't a "what is JSON" tutorial. You know what JSON is. This is the practical guide to working with JSON efficiently: formatting it, validating it, debugging it, and not losing your mind when an API returns a 2MB nested response.
The Real Cost of Messy JSON
Let's quantify this. In a typical API development workflow, you might:
- Inspect 20-50 API responses per day
- Debug 3-5 malformed JSON payloads per week
- Manually format JSON for documentation or tests
If each incident costs you 2-5 minutes of squinting at minified text, that's easily 2-3 hours per week lost to JSON friction. Over a year, that's roughly 130 hours — more than three full work weeks.
The fix isn't complicated. It's just having the right tools and habits.
Quick Wins: JSON Formatting in 30 Seconds
Browser-Based Formatting
For quick one-off formatting, a browser tool is fastest. JSONFormat.co is my go-to because:
- Paste → formatted. No clicking "Format" buttons.
- Syntax errors are highlighted with line numbers
- Collapse/expand nested objects to navigate large payloads
- 100% client-side — your API responses never leave your browser
When to use it: Inspecting API responses, formatting JSON for documentation, quick validation checks.
Command Line Formatting
For scripted workflows:
# Pretty-print with jq
curl -s https://api.example.com/data | jq '.'
# Compact format (minify)
cat data.json | jq -c '.'
# Python one-liner
echo '{"key":"value"}' | python3 -m json.tool
# Node.js one-liner
echo '{"key":"value"}' | node -e "process.stdin.on('data',d=>console.log(JSON.stringify(JSON.parse(d),null,2)))"
When to use it: CI/CD pipelines, automated testing, processing JSON files in bulk.
IDE Integration
Most modern editors handle JSON well:
-
VS Code:
Shift+Alt+Fformats JSON files. Install "Prettier" for opinionated formatting. -
JetBrains IDEs:
Ctrl+Alt+Lauto-formats. JSON schema validation built-in. -
Vim/Neovim:
:%!jq '.'pipes the buffer through jq.
When to use it: Working with JSON config files, API mocks, test fixtures.
JSON Validation: Beyond Syntax Checking
Syntax validation catches missing commas and unclosed brackets. But real-world JSON bugs are sneakier.
Common JSON Gotchas
1. Trailing Commas
{
"name": "test",
"value": 42, // ← This comma will break strict parsers
}
JavaScript tolerates trailing commas in objects. JSON does not. This is the #1 cause of "I swear this JSON is valid" bugs.
2. Single Quotes
{'name': 'test'} // ← Not valid JSON
{"name": "test"} // ← Valid JSON
Python developers hit this constantly. Python's str() uses single quotes by default. Always use json.dumps(), not str().
3. Unquoted Keys
{name: "test"} // ← JavaScript object literal, not JSON
{"name": "test"} // ← Valid JSON
4. NaN and Infinity
{"value": NaN} // ← Not valid JSON
{"value": Infinity} // ← Not valid JSON
{"value": null} // ← Use null instead
JavaScript's JSON.stringify() silently converts NaN to null. But if you're hand-constructing JSON strings, this bites.
5. Duplicate Keys
{
"id": 1,
"name": "first",
"id": 2
}
The JSON spec says behavior for duplicate keys is undefined. Most parsers take the last value, but some take the first. This is a silent bug waiting to happen.
Schema Validation
For production APIs, syntax validation isn't enough. You need JSON Schema:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"required": ["id", "name", "email"],
"properties": {
"id": { "type": "integer", "minimum": 1 },
"name": { "type": "string", "minLength": 1 },
"email": { "type": "string", "format": "email" }
}
}
Tools like ajv (JavaScript) or jsonschema (Python) validate API payloads against schemas at runtime.
Working with Large JSON Responses
When an API returns megabytes of nested JSON, you need strategies beyond "paste it in a formatter."
jq: The Swiss Army Knife
# Extract specific fields
curl -s api.example.com/users | jq '.[].name'
# Filter by condition
curl -s api.example.com/products | jq '.[] | select(.price > 100)'
# Reshape data
curl -s api.example.com/orders | jq '[.[] | {id: .order_id, total: .amount}]'
# Count items
curl -s api.example.com/items | jq 'length'
# Get unique values
curl -s api.example.com/logs | jq '[.[].level] | unique'
Navigation Techniques
When exploring unfamiliar API responses:
-
Start with the shape:
jq 'keys'orjq 'type'to understand top-level structure -
Check array lengths:
jq '.items | length'before trying to display 10,000 records -
Sample first:
jq '.items[:3]'to see the first 3 items - Use a visual tool: JSONFormat.co lets you collapse/expand nodes, which is faster than scrolling through formatted text
Performance Considerations
- Don't log full JSON responses in production. Log the status code, headers, and a truncated body.
- Stream large JSON with libraries like json-stream instead of loading everything into memory.
- Compress in transit. Enable gzip/brotli compression on your API responses. A 2MB JSON response typically compresses to ~200KB.
JSON in Testing
Generating Test Data
For API testing, you need realistic JSON payloads. Here's a practical approach:
- Capture real responses from your API during development
- Anonymize sensitive data — replace real emails, names, and IDs
-
Use generators for specific fields:
- UUIDs → CreateUUID.com
- IBANs → RandomIBAN.co
- Card numbers → Namso.io (test numbers only)
- Store as fixtures in your test suite
JSON Diff for API Testing
When testing API changes, comparing JSON responses catches regressions:
# Compare two JSON files (ignoring key order)
diff <(jq -S '.' old.json) <(jq -S '.' new.json)
# Using jd for semantic diff
jd old.json new.json
JSON Security Considerations
Never Trust Client JSON
Always validate and sanitize JSON from external sources:
// Bad: Direct parse without error handling
const data = JSON.parse(userInput);
// Good: Safe parse with validation
try {
const data = JSON.parse(userInput);
if (!data || typeof data !== 'object') throw new Error('Invalid');
// Validate against schema...
} catch (e) {
return res.status(400).json({ error: 'Invalid JSON' });
}
Prototype Pollution
Be careful with Object.assign() and spread operators on parsed JSON:
// Dangerous if userInput contains "__proto__" keys
const config = { ...defaults, ...JSON.parse(userInput) };
// Safer: use Object.create(null) or a validation library
Use Client-Side Tools for Sensitive Data
If you're formatting JSON that contains API keys, tokens, or PII, use a client-side tool like JSONFormat.co instead of a server-based formatter. Your data shouldn't leave your machine just to add some whitespace.
Putting It All Together
Here's my recommended JSON workflow for API development:
| Task | Tool | Why |
|---|---|---|
| Quick format/validate | JSONFormat.co | Fast, private, no setup |
| CLI processing | jq | Scriptable, powerful filtering |
| IDE formatting | Prettier / built-in | Automatic on save |
| Schema validation | ajv / jsonschema | Catch structural issues |
| API testing | Postman / HTTPie | Built-in JSON handling |
| Test data | Generator tools | Realistic, valid test data |
The goal isn't to use all of these — it's to have the right tool ready when you need it, so you're never wasting time on something that should be automatic.
Part of the Developer Tools Deep Dives series. Follow for more practical guides to the tools and techniques that make API development less painful.
Top comments (0)