Skip to main content

JSON Design Patterns

Learning Focus

Consistent JSON design dramatically reduces integration bugs and support tickets. Apply these patterns from the start of any project.

Naming Conventions

ConventionExampleEcosystem
camelCase (recommended)"firstName"JavaScript, REST APIs
snake_case"first_name"Python, some APIs
PascalCase"FirstName"C# / .NET APIs
kebab-case"first-name"Avoid — invalid in Python identifiers

Pick one and enforce it. Use camelCase for public APIs.

Date and Time

Always use ISO 8601 strings in UTC:

{
"createdAt": "2024-01-15T08:30:00Z",
"updatedAt": "2024-01-15T14:22:31.456Z",
"scheduledFor": "2024-02-01T00:00:00+08:00",
"dateOnly": "2024-01-15"
}

Never use non-standard formats ("Jan 15, 2024") or undocumented Unix timestamps.

Empty vs Null Collections

// ✓ Preferred — client can iterate without null-check
{ "tags": [], "items": [] }

// ✗ Avoid — client must null-check before iteration
{ "tags": null, "items": null }

String IDs for Large Integers

// ✓ Safe — string ID avoids JS precision loss
{ "id": "9007199254740993", "orderId": "ord_abc123" }

// ✗ Risky — integer > 2^53 loses precision in JavaScript
{ "id": 9007199254740993 }

Backwards-Compatible Schema Evolution

OperationSafe?Notes
Add optional fieldClients ignore unknown fields
Add required fieldBreaks existing producers
Remove fieldBreaks existing consumers
Rename fieldBoth keys needed during transition
Change value typeBreaks parsers
Expand enum valuesClients should handle unknown enums

Idempotency Keys

For operations that must not be duplicated:

{
"idempotencyKey": "order-9871-payment-1",
"amount": 129.99,
"currency": "USD"
}

Concept Map

Concept Flow

JSON Design Pillars
├── camelCase keys → Consistent naming
├── ISO 8601 dates → Unambiguous timestamps
├── Empty arrays not null → Safe iteration on client
├── String IDs → No precision loss
├── Schema versioning → Predictable evolution
└── Backwards compatibility → Maintainable API

Common Pitfalls

PitfallConsequencePrevention
Mixed case in same APIClient mapping errorsEnforce via serialiser config
Timestamp without TZAmbiguous local timeAlways use UTC or include offset
null for empty arrayiterable error on clientDefault to []
Renaming without deprecationBreaks all clientsAdd new field; keep old; deprecate with timeline

What's Next