February 20, 2025 - 11 min read

JSON in REST APIs: Best Practices

Design clean, consistent JSON REST API responses. Covers naming conventions, error formats, pagination, and versioning.

apirest

JSON has become the lingua franca of REST APIs. A well-designed JSON response structure makes APIs intuitive to use, reduces support burden, and future-proofs your design as requirements evolve. Conversely, poorly structured JSON responses cause confusion, break client integrations, and generate endless back-and-forth with API consumers.

This guide covers naming conventions, response envelope design, error payloads, pagination patterns, and versioning strategies — everything you need to design REST APIs your consumers will love.

REST API JSON tutorial placement

Advertisement placeholder -- this space is reserved for contextual ads once the site is approved.

Field Naming Conventions

The most important rule: be consistent. Pick one convention and stick to it across your entire API. The three common approaches:

  • camelCase — most common in JavaScript/Node.js APIs (e.g., firstName)
  • snake_case — common in Python and Ruby APIs (e.g., first_name)
  • kebab-case — rare, causes issues as JavaScript object keys

The industry leans toward camelCase for public-facing APIs because most API clients are JavaScript-based. Whichever you choose, document it explicitly in your API reference.

// ✅ Consistent camelCase
{
  "userId": 123,
  "firstName": "Alice",
  "lastName": "Smith",
  "createdAt": "2025-01-01T08:00:00Z",
  "isActive": true
}

// ❌ Inconsistent — avoid
{
  "user_id": 123,
  "FirstName": "Alice",
  "last-name": "Smith"
}

Response Envelope Design

Wrap your responses in a consistent envelope so clients always know where to find data, errors, and metadata:

// Single resource
{
  "data": {
    "id": 123,
    "name": "Alice Smith",
    "email": "alice@example.com"
  },
  "meta": {
    "requestId": "req_abc123",
    "timestamp": "2025-01-01T08:00:00Z"
  }
}

// Collection response
{
  "data": [
    { "id": 1, "name": "Alice" },
    { "id": 2, "name": "Bob" }
  ],
  "meta": {
    "total": 150,
    "page": 1,
    "perPage": 2
  }
}

Never return a bare array at the top level — adding metadata later will be a breaking change. Wrapping in data from day one costs nothing and buys you flexibility.

Mid-article REST API JSON placement

Advertisement placeholder -- this space is reserved for contextual ads once the site is approved.

Consistent Error Payloads

Errors are part of your API contract. Use a consistent structure so clients can handle errors generically:

// HTTP 422 Unprocessable Entity
{
  "error": {
    "code": "VALIDATION_FAILED",
    "message": "The request body failed validation.",
    "details": [
      {
        "field": "email",
        "code": "INVALID_FORMAT",
        "message": "Must be a valid email address."
      },
      {
        "field": "age",
        "code": "OUT_OF_RANGE",
        "message": "Must be between 0 and 150."
      }
    ],
    "requestId": "req_abc123",
    "documentationUrl": "https://docs.example.com/errors/VALIDATION_FAILED"
  }
}

Including a documentationUrl field pointing to your error reference docs dramatically reduces support tickets from developers.

Use HTTP Status Codes Correctly

  • 200 — success
  • 201 — resource created (POST)
  • 204 — success, no body (DELETE)
  • 400 — bad request (client error in request format)
  • 401 — unauthorized (not authenticated)
  • 403 — forbidden (authenticated but not allowed)
  • 404 — resource not found
  • 422 — validation failed
  • 429 — rate limit exceeded
  • 500 — internal server error

Pagination Patterns

For collections, always paginate. The two common approaches:

// Offset-based pagination (simple, familiar)
{
  "data": [...],
  "pagination": {
    "page": 2,
    "perPage": 20,
    "total": 450,
    "totalPages": 23
  }
}

// Cursor-based pagination (better for large/live datasets)
{
  "data": [...],
  "pagination": {
    "nextCursor": "eyJpZCI6MTAwfQ==",
    "hasMore": true
  }
}

Prefer cursor-based pagination for large datasets or real-time feeds — it handles insertions and deletions between pages gracefully, unlike offset pagination which can skip or repeat items.

Date and Time Formatting

Always use ISO 8601 format with UTC timezone for all timestamps. Never return Unix timestamps or locale-specific date strings:

// ✅ ISO 8601 UTC
"createdAt": "2025-01-15T08:30:00Z"

// ✅ With timezone offset
"scheduledAt": "2025-01-15T14:00:00+05:30"

// ❌ Avoid Unix timestamps (ambiguous ms vs seconds)
"createdAt": 1736929800

// ❌ Avoid locale-specific formats
"createdAt": "15/01/2025"

Key Takeaways

  • Pick one naming convention (camelCase recommended) and apply it everywhere
  • Wrap responses in a data envelope — never return bare arrays
  • Use consistent error payloads with machine-readable code fields
  • Use HTTP status codes correctly — don't return 200 for errors
  • Prefer cursor-based pagination for large collections
  • Use ISO 8601 UTC for all timestamps
  • Use JSONStudio to validate and format your API responses during development

Continue learning

How APIs Use JSON

A tour of REST, GraphQL, and even event-driven payload design with JSON as the interoperable contract.

Jan 13, 2025 · 10 min read

What is JSON?

A foundational tour of JSON covering syntax, design goals, and why it became the lingua franca for data on the web.

Jan 5, 2025 · 9 min read

How JSON Works

Learn how parsers tokenize documents, how serialization travels across the network, and ways to debug encoding bugs.

Jan 6, 2025 · 10 min read