Why JSON API design matters more than you think
A poorly designed JSON API doesn't just frustrate the developers integrating with it — it creates real business costs. Ambiguous field names lead to bugs in production. Inconsistent date formats cause parsing errors across time zones. Missing pagination causes mobile apps to download gigabytes of unnecessary data. Every API design decision has downstream consequences.
These are the practices I've learned from integrating with hundreds of APIs and building my own.
1. Use camelCase for field names (consistently)
Pick one naming convention and stick to it throughout your entire API. The JavaScript ecosystem expects camelCase (firstName). Python and Ruby developers often prefer snake_case (first_name). The wrong choice doesn't matter — inconsistency does. An API that uses userId in one endpoint and user_id in another is a maintenance nightmare.
2. Always return the same shape
The most common API frustration: a field that is sometimes a string, sometimes a number, sometimes null, and sometimes missing entirely. Every field should have a consistent type. If a value is optional, it should always be present — either with a value or as null. Never simply omit it when empty.
3. Use ISO 8601 for all dates and times
Always. No exceptions. The format is 2026-05-06T14:30:00Z. Never return dates as Unix timestamps without documentation, never return locale-specific formats like "05/06/2026" (is that May 6th or June 5th?), and never return date strings without timezone information. ISO 8601 is unambiguous and parseable by every language's standard library.
4. Paginate everything that returns lists
Any endpoint that returns a collection should support pagination. Even if you only have 10 items today, you'll have 100,000 tomorrow. Cursor-based pagination (returning a nextCursor token) is better than offset-based pagination for large datasets — it's consistent when items are added or deleted between pages.
5. Return useful error objects
A 400 response with body {"error": "Bad request"} is useless. A good error response tells the client exactly what went wrong:
{"error": {"code": "INVALID_EMAIL", "message": "The email field must be a valid email address", "field": "email"}}
Include a machine-readable error code, a human-readable message, and (where applicable) the specific field that caused the error.
6. Version your API from day one
Put the version in the URL path: /v1/users, /v2/users. Never in a header — headers are invisible to browser caches and load balancers. Versioning allows you to make breaking changes without breaking existing integrations. The cost of not versioning is enormous — you become trapped by your first design decisions forever.
7. Use HTTP status codes correctly
200 for success. 201 for created. 204 for success with no response body. 400 for client errors (bad request). 401 for unauthenticated. 403 for unauthorized (authenticated but not allowed). 404 for not found. 422 for validation errors. 429 for rate limited. 500 for server errors. The cardinal sin: returning 200 with {"success": false} — that breaks every HTTP client's error handling.