alltools.one
APIβ€’
2025-06-05
β€’
7 min
β€’
alltools.one Team
APIRESTJSONResponse FormatBest Practices

API Response Formats: Best Practices for Consistent APIs

Inconsistent API responses are a top complaint from frontend developers. When every endpoint returns data in a different shape, client code becomes littered with special cases. A consistent response format improves developer experience, reduces bugs, and makes your API self-documenting.

The Response Envelope

Wrap every response in a consistent structure:

Success (Single Resource)

{
  "data": {
    "id": "user_123",
    "name": "Alice",
    "email": "alice@example.com",
    "createdAt": "2024-01-15T10:30:00Z"
  },
  "meta": {
    "requestId": "req_abc123"
  }
}

Success (Collection)

{
  "data": [
    { "id": "user_123", "name": "Alice" },
    { "id": "user_456", "name": "Bob" }
  ],
  "meta": {
    "total": 142,
    "page": 1,
    "perPage": 20,
    "requestId": "req_def456"
  }
}

Error

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "details": [
      { "field": "email", "message": "Invalid email format" }
    ]
  },
  "meta": {
    "requestId": "req_ghi789"
  }
}

The key principle: clients always check for data or error at the top level. Never mix success data and error information in the same response.

Validate your response format with our JSON Validator.

HTTP Status Codes

Use status codes correctly β€” they are the first thing clients check:

Success Codes

CodeWhen
200 OKGET success, PUT/PATCH success
201 CreatedPOST that created a resource
204 No ContentDELETE success (no body)

Client Error Codes

CodeWhen
400 Bad RequestMalformed request syntax
401 UnauthorizedMissing or invalid authentication
403 ForbiddenAuthenticated but not authorized
404 Not FoundResource does not exist
409 ConflictResource state conflict (duplicate)
422 UnprocessableValid syntax but semantic errors
429 Too Many RequestsRate limit exceeded

Server Error Codes

CodeWhen
500 Internal Server ErrorUnexpected server failure
502 Bad GatewayUpstream service failure
503 Service UnavailableTemporary overload or maintenance

Error Response Design

Good error responses help developers debug quickly:

{
  "error": {
    "code": "RESOURCE_NOT_FOUND",
    "message": "User with ID 'user_999' not found",
    "details": [],
    "documentationUrl": "https://api.example.com/docs/errors#RESOURCE_NOT_FOUND"
  },
  "meta": {
    "requestId": "req_xyz789",
    "timestamp": "2024-01-15T10:30:00Z"
  }
}

Rules:

  • code is machine-readable (constant string, not HTTP status)
  • message is human-readable (can change without breaking clients)
  • details provides field-level errors for validation failures
  • requestId enables support team to trace the request in logs

Pagination Patterns

Offset-Based

Simple and supports jumping to arbitrary pages:

{
  "data": ["..."],
  "meta": {
    "page": 2,
    "perPage": 20,
    "total": 142,
    "totalPages": 8
  },
  "links": {
    "first": "/api/users?page=1&per_page=20",
    "prev": "/api/users?page=1&per_page=20",
    "next": "/api/users?page=3&per_page=20",
    "last": "/api/users?page=8&per_page=20"
  }
}

Cursor-Based

Better for real-time data and large datasets:

{
  "data": ["..."],
  "meta": {
    "hasNext": true,
    "hasPrev": true
  },
  "links": {
    "next": "/api/users?cursor=eyJpZCI6MTQzfQ&limit=20",
    "prev": "/api/users?cursor=eyJpZCI6MTIzfQ&limit=20&direction=prev"
  }
}

Date and Time

Always use ISO 8601 with timezone information:

{
  "createdAt": "2024-01-15T10:30:00Z",
  "updatedAt": "2024-01-15T14:22:33+00:00",
  "expiresAt": "2024-12-31T23:59:59Z"
}

Never use:

  • Unix timestamps (ambiguous: seconds or milliseconds?)
  • Local dates without timezone
  • Custom formats like MM/DD/YYYY

For more on timestamp handling, see our Unix Timestamps guide.

Null vs Absent Fields

Two common approaches:

Include with null (explicit):

{ "name": "Alice", "avatar": null, "bio": null }

Omit absent fields (sparse):

{ "name": "Alice" }

Recommendation: Be consistent within your API. Explicit nulls are better for typed languages (clients know the field exists). Sparse is better for bandwidth-constrained environments.

Versioning Responses

When response format changes, version your API:

GET /api/v2/users/123

Breaking changes that require versioning:

  • Removing a field
  • Changing a field type
  • Renaming a field
  • Changing the response envelope structure

Non-breaking changes (safe without versioning):

  • Adding new fields
  • Adding new endpoints
  • Adding new enum values

FAQ

Should I wrap successful responses in a data key or return the resource directly?

Using a data wrapper provides a consistent structure for all responses and leaves room for metadata, pagination, and links alongside the data. Returning the resource directly is simpler for single-resource endpoints. Most modern APIs use the wrapper approach for consistency.

How should I handle partial failures in batch operations?

Return 200 with a response that includes both successes and failures in the data object. Using 207 Multi-Status (WebDAV) is another option but less commonly used in REST APIs.

Related Resources

Published on 2025-06-05
API Response Formats: Best Practices for Consistent APIs | alltools.one