JSON API Standard
JSON:API is a specification for building REST APIs that use JSON. It defines a consistent structure for requests and responses so that client and server teams can communicate clearly without arguing about format decisions. When APIs follow JSON:API, any client that understands the standard can work with any compatible server.
Why JSON:API Exists
Every developer building a REST API makes dozens of small decisions. How should a list of items be wrapped? How should errors be formatted? How should related data be included? Without a standard, every API looks different. Teams spend time negotiating these decisions instead of building features.
Think of JSON:API like a standardized shipping container. Before shipping containers existed, every ship and port had to deal with a different box size and shape. After standardization, any container fits any ship and any crane. JSON:API does the same for APIs.
JSON:API Content Type
APIs that follow JSON:API must use this Content-Type header:
Content-Type: application/vnd.api+json
Basic JSON:API Response Structure
A JSON:API response has a predictable structure with specific keys.
Single Resource Response
{
"data": {
"type": "articles",
"id": "1",
"attributes": {
"title": "Getting Started with JSON",
"body": "JSON is a lightweight data format...",
"publishedAt": "2026-01-15",
"readTime": 5
},
"relationships": {
"author": {
"data": { "type": "people", "id": "42" }
},
"tags": {
"data": [
{ "type": "tags", "id": "10" },
{ "type": "tags", "id": "11" }
]
}
},
"links": {
"self": "https://api.example.com/articles/1"
}
}
}
Collection Response (Multiple Resources)
{
"data": [
{
"type": "articles",
"id": "1",
"attributes": {
"title": "Getting Started with JSON",
"publishedAt": "2026-01-15"
}
},
{
"type": "articles",
"id": "2",
"attributes": {
"title": "JSON Schema Explained",
"publishedAt": "2026-02-20"
}
}
],
"meta": {
"total": 47,
"page": 1,
"perPage": 2
},
"links": {
"self": "https://api.example.com/articles?page=1",
"next": "https://api.example.com/articles?page=2",
"last": "https://api.example.com/articles?page=24"
}
}
Diagram: JSON:API Document Structure
JSON:API Document
├── data ← Main resource or array of resources
│ ├── type ← Resource type name (e.g., "articles", "users")
│ ├── id ← Unique identifier (always a string)
│ ├── attributes ← The actual data fields (not id, not relationships)
│ └── relationships ← Links to related resources
├── included ← Related resource data (sideloaded, optional)
├── meta ← Non-data info: pagination, totals, etc.
├── links ← URLs: self, next, prev, first, last
└── errors ← Error objects (replaces "data" when errors occur)
Key Rules of JSON:API
1. type and id are Always Present
Every resource object must have a type (what kind of resource it is) and an id (the unique identifier). The id is always a string, even if it is a number in your database.
{
"type": "users",
"id": "301" // "301" as a string, not 301 as a number
}
2. attributes Holds the Data Fields
All data fields go inside attributes. The id and type stay at the same level as attributes, not inside it.
"attributes": {
"name": "Priya Mehta",
"email": "priya@example.com",
"joinedAt": "2025-06-01"
}
3. relationships Connects Resources
Instead of embedding a full author object inside an article, JSON:API uses a relationships section with just the type and id of the related resource. The full related data can optionally appear in the included section.
"relationships": {
"author": {
"data": { "type": "people", "id": "42" }
}
}
The included Section (Sideloading)
Sideloading means including related resource data in the same response to avoid a second network request. The included array holds full resource objects for all referenced relationships.
{
"data": {
"type": "articles",
"id": "1",
"attributes": { "title": "Getting Started with JSON" },
"relationships": {
"author": {
"data": { "type": "people", "id": "42" }
}
}
},
"included": [
{
"type": "people",
"id": "42",
"attributes": {
"name": "Arjun Sharma",
"bio": "Senior developer and technical writer"
}
}
]
}
The article references author with id "42." The full author data appears in included. The client assembles the complete picture from these two sections.
JSON:API Error Response
When something goes wrong, JSON:API uses a standardized errors array instead of data.
{
"errors": [
{
"id": "ERR-001",
"status": "422",
"code": "VALIDATION_FAILED",
"title": "Unprocessable Entity",
"detail": "The email field must contain a valid email address.",
"source": {
"pointer": "/data/attributes/email"
}
}
]
}
Error Object Fields
Field Meaning
----- -------
id Unique ID for this specific error occurrence
status HTTP status code as a string
code Application-specific error code
title Short, human-readable summary
detail Longer explanation specific to this occurrence
source Pointer to the field that caused the error
JSON:API Request: Creating a Resource
POST /articles HTTP/1.1
Content-Type: application/vnd.api+json
{
"data": {
"type": "articles",
"attributes": {
"title": "JSON Patch Explained",
"body": "JSON Patch allows partial updates...",
"publishedAt": "2026-09-01"
},
"relationships": {
"author": {
"data": { "type": "people", "id": "42" }
}
}
}
}
JSON:API Request: Updating a Resource
PATCH /articles/1 HTTP/1.1
Content-Type: application/vnd.api+json
{
"data": {
"type": "articles",
"id": "1",
"attributes": {
"title": "JSON Patch Explained (Updated)"
}
}
}
Filtering, Sorting, and Pagination in JSON:API
JSON:API recommends query parameter conventions for common operations:
GET /articles?filter[status]=published Filter by status
GET /articles?sort=-publishedAt Sort by date (- means descending)
GET /articles?sort=title Sort by title (ascending)
GET /articles?page[number]=2&page[size]=10 Get page 2 with 10 items
GET /articles?include=author,tags Sideload author and tags
GET /articles?fields[articles]=title,body Sparse fieldsets (only get some fields)
JSON:API vs Plain REST JSON
Feature Plain REST JSON:API
------- ---------- --------
Response structure Varies by team Standardized
Error format Varies Standardized errors array
Relationships Embedded (nested) Normalized with included
Pagination info Custom meta + links
Content-Type application/json application/vnd.api+json
Client tooling support Generic JSON:API-aware libraries
Learning curve Low Moderate
JSON:API Libraries
- JavaScript: jsonapi-serializer, json-api-client
- Python: marshmallow-jsonapi, flask-rest-jsonapi
- Ruby: JSONAPI::Resources (Rails)
- PHP: laravel-json-api
- Java: katharsis
When to Use JSON:API
JSON:API is a great choice when your team is building a large API that multiple clients will consume (web, mobile, third parties), when you want to standardize response formats across many endpoints, or when you want to support features like sparse fieldsets and relationship sideloading out of the box.
For small, single-team projects or simple CRUD APIs, plain JSON with consistent conventions is often sufficient. JSON:API adds structure but also adds weight.
Summary
JSON:API is a specification that defines a standard structure for REST API requests and responses. It uses data, type, id, attributes, relationships, included, meta, links, and errors as the building blocks of every response. It standardizes filtering, sorting, pagination, and error reporting through query parameter conventions. Use it when consistency across many API endpoints and clients is more important than simplicity.
