·7 min read
JSON API Design Standards: Building Consistent APIs
JSON API design standards define how JSON should be structured in web APIs to ensure consistency, predictability, and developer experience. From JSON:API and JSend to custom conventions, choosing the right standard impacts everything from client library generation to API documentation. This guide covers the major JSON API standards, their pros and cons, and practical implementation guidance. Use our JSON Formatter to format API responses and JSON to OpenAPI to generate API specifications.
Major JSON API Standards
| Standard | Best For | Key Feature | Specification |
|---|---|---|---|
| JSON:API | Complex resource APIs with relationships | Compound documents, resource linkage, sparse fieldsets | jsonapi.org |
| JSend | Simple CRUD APIs | Standardized response envelope with status, data, and error | GitHub (informal) |
| REST response envelope | Microservices | Status + data + meta + error at top level | No formal spec |
| GraphQL | Flexible, client-driven queries | Single endpoint, client selects fields | graphql.org |
| OData | Enterprise data services | Rich query language, metadata, CRUD operations | odata.org |
| RFC 7807 (Problem Details) | Error responses | Standard error format with type, title, status, detail | RFC 7807 |
JSON:API Response Format
// JSON:API response
GET /api/articles/1?include=author,comments
{
"data": {
"type": "articles",
"id": "1",
"attributes": {
"title": "JSON API Design",
"body": "Content here...",
"createdAt": "2025-01-15T10:00:00Z"
},
"relationships": {
"author": {
"data": { "type": "people", "id": "42" }
},
"comments": {
"data": [
{ "type": "comments", "id": "1" },
{ "type": "comments", "id": "2" }
]
}
}
},
"included": [
{
"type": "people",
"id": "42",
"attributes": {
"name": "Alice",
"email": "alice@example.com"
}
},
{
"type": "comments",
"id": "1",
"attributes": {
"body": "Great article!",
"createdAt": "2025-01-15T11:00:00Z"
}
}
]
}
JSend Response Format
// JSend: success
{
"status": "success",
"data": {
"user": { "id": 1, "name": "Alice", "email": "alice@example.com" }
}
}
// JSend: fail (validation errors)
{
"status": "fail",
"data": {
"email": "Email is already taken",
"password": "Password must be at least 8 characters"
}
}
// JSend: error (server error)
{
"status": "error",
"message": "Unable to connect to database",
"code": 500
}
Simple Response Envelope (Custom)
// Success
{
"success": true,
"data": { ... },
"meta": {
"requestId": "req_abc",
"timestamp": "2025-01-15T10:00:00Z",
"version": "2.1"
}
}
// Error
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "The request contains invalid fields",
"details": [
{ "field": "email", "message": "Invalid format" },
{ "field": "age", "message": "Must be 18 or older" }
]
}
}
// Paginated response
{
"success": true,
"data": [...],
"pagination": {
"page": 1,
"perPage": 20,
"total": 156,
"hasMore": true
}
}
RFC 7807 Problem Details (Error Responses)
HTTP/1.1 429 Too Many Requests
Content-Type: application/problem+json
{
"type": "https://api.example.com/errors/rate-limit",
"title": "Rate Limit Exceeded",
"status": 429,
"detail": "You have exceeded the limit of 100 requests per minute.",
"instance": "/api/users",
"retryAfter": 45
}
// Standard fields:
// type - URI identifying the problem type
// title - Short, human-readable summary
// status - HTTP status code
// detail - Human-readable explanation
// instance - URI identifying the specific occurrence
Choosing the Right Standard
| Criterion | JSON:API | JSend | Custom Envelope | GraphQL |
|---|---|---|---|---|
| Learning curve | Steep | Gentle | None | Moderate |
| Client/tooling support | Excellent (many client libraries) | Minimal | None | Excellent |
| Flexibility | High (sparse fields, includes) | Low | Maximum | Very high |
| Self-documenting | Yes (media type) | No | No | Yes (schema) |
| Best for | Public APIs, CRUD resources | Internal APIs, simple services | Microservices, BFFs | Complex data, mobile apps |
API Design Best Practices
- Pick one standard and apply it consistently across all endpoints
- Always include a request ID in responses for debugging
- Use consistent HTTP status codes alongside JSON status fields
- Validate all request JSON with JSON Validator patterns
- Consider JSON:API for public APIs, JSend for internal services
- Use RFC 7807 for error responses in production APIs
- Document your API with OpenAPI/Swagger using JSON to OpenAPI
Next Steps
Generate OpenAPI specs from your JSON with JSON to OpenAPI. Format API responses with JSON Formatter. Validate API payloads with JSON Validator.