A Complete Introduction to the JSON:API Specification

This comprehensive guide offers a deep dive into the JSON:API specification, exploring its core concepts, structure, and powerful features.

Rebecca Kovács

Rebecca Kovács

19 May 2025

A Complete Introduction to the JSON:API Specification

REST (Representational State Transfer) provides a foundational architectural style for building web services. However, it leaves many aspects of request and response formatting undefined. This ambiguity can lead to inconsistencies, increased development overhead, and a steeper learning curve for API consumers. Enter JSON:API, a specification that provides a standardized, convention-based approach to building APIs in JSON.

This comprehensive guide offers a deep dive into the JSON:API specification, exploring its core concepts, structure, and powerful features. We will dissect its mechanisms for fetching, creating, updating, and deleting resources, managing relationships, handling errors, and optimizing data transfer, equipping you with the knowledge to design and consume robust and efficient APIs.

💡
Want a great API Testing tool that generates beautiful API Documentation?

Want an integrated, All-in-One platform for your Developer Team to work together with maximum productivity?

Apidog delivers all your demans, and replaces Postman at a much more affordable price!
button

Why JSON:API? Explained:

Before delving into the technical intricacies, it's crucial to understand the problems JSON:API aims to solve. Without a shared convention, API developers often spend considerable time debating:

JSON:API addresses these by defining a clear, consistent format for requests and responses. This standardization offers several key benefits:

Core Concepts: The Building Blocks of a JSON:API Document

At its heart, JSON:API revolves around the concept of resources. A resource is an individual record of a particular type, such as an "article," a "user," or a "product." Every JSON:API document, whether a request or a response, adheres to a specific structure.

The Document Structure: Top-Level Members

A JSON:API document is a JSON object that must contain at least one of the following top-level members:

Additionally, a document may contain these top-level members:

Resource Objects: Representing Your Data

A resource object is the cornerstone of JSON:API and must contain:

A resource object may also contain:

Example of a Resource Object:JSON

{
  "type": "articles",
  "id": "1",
  "attributes": {
    "title": "JSON:API Unveiled",
    "body": "A deep dive into the specification...",
    "created_at": "2025-05-15T10:00:00Z",
    "updated_at": "2025-05-16T14:30:00Z"
  },
  "relationships": {
    "author": {
      "links": {
        "self": "/articles/1/relationships/author",
        "related": "/articles/1/author"
      },
      "data": { "type": "users", "id": "42" }
    },
    "comments": {
      "links": {
        "self": "/articles/1/relationships/comments",
        "related": "/articles/1/comments"
      },
      "data": [
        { "type": "comments", "id": "5" },
        { "type": "comments", "id": "12" }
      ]
    }
  },
  "links": {
    "self": "/articles/1"
  }
}

Resource Identifier Objects

Resource identifier objects are minimal representations of a resource, containing only type and id. They are used within relationship objects to link to other resources without embedding the full resource object.

Example of a Resource Identifier Object:JSON

{ "type": "users", "id": "42" }

Links objects provide URLs for navigating the API. Common link members include:

A link can be represented as:

Example of a Links Object (within a relationship):JSON

"links": {
  "self": "http://example.com/articles/1/relationships/author",
  "related": "http://example.com/articles/1/author"
}

Meta Objects

Meta objects allow for the inclusion of non-standard meta-information. This can be arbitrary key-value pairs. For instance, a meta object could include copyright information or timestamps related to the data.

Example of a Meta Object:JSON

"meta": {
  "copyright": "Copyright 2025 Example Corp.",
  "authors": ["John Doe"]
}

Content Negotiation: Speaking the Right Language

JSON:API defines its own media type: application/vnd.api+json.

Servers can support other media types alongside application/vnd.api+json through standard content negotiation.

Fetching Data: Retrieving Resources and Collections

JSON:API provides robust mechanisms for clients to retrieve data precisely as needed.

Fetching Individual Resources

To fetch a single resource, a client sends a GET request to an endpoint representing that resource.

Request:

GET /articles/1

Accept: application/vnd.api+json

Successful Response (200 OK):JSON

{
  "links": {
    "self": "/articles/1"
  },
  "data": {
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "JSON:API Rocks!"
    }
    // ... other attributes and relationships
  }
}

If the resource does not exist, the server should return a 404 Not Found. If a to-one related resource link is fetched and the relationship is empty, the primary data will be null.

Fetching Collections of Resources

To fetch a collection of resources, a client sends a GET request to an endpoint representing that collection.

Request:

GET /articles

Accept: application/vnd.api+json

Successful Response (200 OK):JSON

{
  "links": {
    "self": "/articles",
    "next": "/articles?page[offset]=10",
    "last": "/articles?page[offset]=50"
  },
  "data": [
    {
      "type": "articles",
      "id": "1",
      "attributes": { "title": "Article 1" }
      // ...
    },
    {
      "type": "articles",
      "id": "2",
      "attributes": { "title": "Article 2" }
      // ...
    }
    // ... more articles
  ]
}

If the collection is empty, the data member will be an empty array [].

Relationships: Connecting Resources

Relationships are a fundamental part of most data models. JSON:API provides a clear way to define and interact with them.

Representing Relationships

Relationships are defined within the relationships object of a resource. Each entry in the relationships object represents a distinct relationship (e.g., "author," "comments").

A relationship object must contain at least one of:

Example of "author" (to-one) and "comments" (to-many) relationships:JSON

"relationships": {
  "author": {
    "links": {
      "self": "/articles/1/relationships/author",
      "related": "/articles/1/author"
    },
    "data": { "type": "users", "id": "42" }
  },
  "comments": {
    "links": {
      "self": "/articles/1/relationships/comments",
      "related": "/articles/1/comments"
    },
    "data": [
      { "type": "comments", "id": "5" },
      { "type": "comments", "id": "12" }
    ]
  }
}

Fetching Relationships

Clients can fetch information about a relationship itself or the related resources using the links provided.

Fetching Relationship Linkage (self link):

GET /articles/1/relationships/comments

Accept: application/vnd.api+json

This returns a collection of resource identifier objects for the comments related to article "1".

Fetching Related Resources (related link):

GET /articles/1/comments

Accept: application/vnd.api+json

This returns a collection of full comment resource objects related to article "1".

Optimizing Data Retrieval

JSON:API offers several features to optimize how data is retrieved, minimizing bandwidth and improving client-side performance.

Compound Documents: Reducing HTTP Requests with include

To avoid multiple round trips to the server for fetching related resources, JSON:API allows clients to request that related resources be included in the primary response using the include query parameter. The server will then sideload these resources into the top-level included array.

Request to fetch an article and include its author and comments:

GET /articles/1?include=author,comments

Accept: application/vnd.api+json

Response (200 OK):JSON

{
  "data": {
    "type": "articles",
    "id": "1",
    "attributes": { "title": "..." },
    "relationships": {
      "author": {
        "data": { "type": "users", "id": "42" }
      },
      "comments": {
        "data": [
          { "type": "comments", "id": "5" },
          { "type": "comments", "id": "12" }
        ]
      }
    }
  },
  "included": [
    {
      "type": "users",
      "id": "42",
      "attributes": { "name": "John Doe" }
    },
    {
      "type": "comments",
      "id": "5",
      "attributes": { "body": "Great article!" }
    },
    {
      "type": "comments",
      "id": "12",
      "attributes": { "body": "Very informative." }
    }
  ]
}

Sparse Fieldsets: Fetching Only Necessary Fields

Clients can request that only specific fields (attributes and relationships) be returned for resources of a given type using the fields[TYPE] query parameter. This reduces payload size.

Request to fetch articles, but only their title and author relationship:

GET /articles?fields[articles]=title,author

Accept: application/vnd.api+json

Response (200 OK):JSON

{
  "data": [
    {
      "type": "articles",
      "id": "1",
      "attributes": {
        "title": "Article 1"
      },
      "relationships": {
        "author": {
          "data": { "type": "users", "id": "42" }
        }
      }
    }
    // ... other articles with only title and author
  ]
}

Sorting

Clients can request that the primary data be sorted using the sort query parameter.

Request to fetch articles sorted by creation date (descending) and then title (ascending):

GET /articles?sort=-created_at,title

Accept: application/vnd.api+json

Pagination

JSON:API supports various pagination strategies. The specification defines how pagination links (first, prev, next, last) should appear in the top-level links object. The actual pagination strategy (e.g., page-based, offset-based, cursor-based) is determined by the server using query parameters like page[number], page[size], page[offset], page[limit], or page[cursor].

Example of page-based pagination links:JSON

"links": {
  "self": "/articles?page[number]=2&page[size]=10",
  "first": "/articles?page[number]=1&page[size]=10",
  "prev": "/articles?page[number]=1&page[size]=10",
  "next": "/articles?page[number]=3&page[size]=10",
  "last": "/articles?page[number]=5&page[size]=10"
}

Clients should use these provided links rather than constructing their own pagination URLs.

Filtering

The specification reserves the filter query parameter for filtering data. However, it does not mandate a specific filtering strategy. Servers can implement any strategy, such as filter[attribute]=value or more complex expression-based filtering.

Example (recommended by JSON:API, but not mandated):

GET /comments?filter[post]=1 (Get comments for post with ID 1)

GET /comments?filter[post]=1,2&filter[author]=12 (Get comments for posts 1 or 2, by author 12)

Clients should consult the API's documentation to understand its specific filtering capabilities.

Modifying Data: Creating, Updating, and Deleting Resources

JSON:API defines clear protocols for data manipulation operations.

Creating Resources

To create a resource, a client sends a POST request to a URL representing a collection of resources. The request body must contain a single resource object with type and, optionally, attributes and relationships. The client must not provide an id for the new resource (unless client-generated IDs are supported and enabled).

Request:

POST /articles

Accept: application/vnd.api+json

Content-Type: application/vnd.api+jsonJSON

{
  "data": {
    "type": "articles",
    "attributes": {
      "title": "New Article Title",
      "body": "Content of the new article."
    },
    "relationships": {
      "author": {
        "data": { "type": "users", "id": "42" }
      }
    }
  }
}

Successful Responses:

If an attempt is made to create a resource with a client-generated ID that already exists, and the server doesn't support updating via POST, it must return 409 Conflict.

Updating Resources

Resources are updated using the PATCH HTTP method. The request must include the id of the resource to be updated. The request body contains a resource object with type, id, and the attributes and/or relationships to be updated.

Request to update an article's title and one of its relationships:

PATCH /articles/1

Accept: application/vnd.api+json

Content-Type: application/vnd.api+jsonJSON

{
  "data": {
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "Updated Article Title"
    },
    "relationships": {
      "tags": {
        "data": [
          { "type": "tags", "id": "3" },
          { "type": "tags", "id": "4" }
        ]
      }
    }
  }
}

Key points for updates:

Successful Responses:

If the resource to be updated does not exist, the server must return 404 Not Found.

Updating Relationships Directly

JSON:API provides specific ways to manage relationships without affecting the primary resource's attributes.

{
  "data": { "type": "users", "id": "24" } // Assign new author or null to clear
}
{
  "data": [
    { "type": "comments", "id": "101" },
    { "type": "comments", "id": "102" }
  ]
}
{
  "data": [
    { "type": "comments", "id": "103" }
  ]
}
{
  "data": [
    { "type": "comments", "id": "5" }
  ]
}

Successful relationship updates usually return 200 OK or 204 No Content.

Deleting Resources

To delete a resource, a client sends a DELETE request to the resource's endpoint.

Request:

DELETE /articles/1

Accept: application/vnd.api+json

Successful Response:

If the resource does not exist, the server should return 404 Not Found. The specification does not dictate how related resources or relationships should be handled upon deletion (e.g., cascading deletes); this is an implementation detail.

Error Handling

When an error occurs, servers must use appropriate HTTP status codes (4xx for client errors, 5xx for server errors). The response body should contain a JSON:API error document.

An error document includes a top-level errors member, which is an array of error objects. Each error object can contain:

Example Error Response (422 Unprocessable Entity):JSON

{
  "errors": [
    {
      "status": "422",
      "source": { "pointer": "/data/attributes/email" },
      "title": "Invalid Attribute",
      "detail": "The email address is not valid."
    },
    {
      "status": "422",
      "source": { "pointer": "/data/relationships/author" },
      "title": "Invalid Relationship Value",
      "detail": "Author with ID '999' does not exist."
    }
  ]
}

Server-Side Considerations and Best Practices

While the core specification is comprehensive, JSON:API also provides recommendations for aspects like URL design and member naming.

URL Design

Member Naming

Extending the Specification: Extensions and Profiles

JSON:API is designed to be extensible to cater to evolving needs and specific use cases.

Extensions

Extensions can introduce new functionality not covered by the base specification. An example is the "Atomic Operations" extension, which allows multiple operations (create, update, delete) to be performed in a single, atomic request. Both client and server must understand an extension for it to be used. If a server receives a request with an unsupported extension, it must respond with an appropriate error.

Profiles

Profiles define a set of conventions on top of the base specification for a particular use case (e.g., a specific way to handle timestamps or a common set of meta attributes). Unlike extensions, profiles can be safely ignored if not understood by one party. They are intended to promote interoperability for common patterns without requiring changes to the core specification or mandating universal support.

Servers can advertise supported extensions and profiles in the top-level jsonapi object. This allows clients to discover these capabilities and tailor their requests accordingly.

The Future of JSON:API

JSON:API continues to evolve, driven by community input and the need to address emerging API design challenges. Its focus on convention over configuration, efficiency, and developer experience has solidified its place as a leading standard for building modern APIs. By adopting JSON:API, development teams can significantly reduce ambiguity, enhance interoperability, and accelerate the pace of API development and consumption.

This detailed exploration covers the vast majority of the JSON:API specification. By understanding and implementing these principles, developers can create APIs that are not only functional but also clean, consistent, and a pleasure to work with, ultimately fostering a more productive and collaborative API ecosystem.

Explore more

How Much Does Claude API Cost in 2025

How Much Does Claude API Cost in 2025

Anthropic Claude has emerged as a powerful and versatile large language model (LLM), captivating developers and businesses with its advanced reasoning, creativity, and commitment to safety. As with any powerful tool, understanding the associated costs is paramount for effective implementation and sustainable innovation. This comprehensive tutorial will guide you through the intricacies of Claude API pricing, empowering you to make informed decisions and accurately forecast your expenses as you h

8 June 2025

How to Fix "Due to unexpected capacity constraints, Claude is unable to respond to your message" Error

How to Fix "Due to unexpected capacity constraints, Claude is unable to respond to your message" Error

It's a frustration familiar to many users of cutting-edge AI: you're deep in a productive workflow with Anthropic's Claude, crafting the perfect prompt, only to be met with the abrupt and unhelpful message: "Due to unexpected capacity constraints, Claude is unable to respond to your message. Please try again soon." This digital roadblock can halt creativity and productivity in their tracks, leaving users wondering what went wrong and how to get back on course. This comprehensive guide will delve

8 June 2025

A Developer's Guide: How to Generate API Specifications with Vercel v0 Workflows

A Developer's Guide: How to Generate API Specifications with Vercel v0 Workflows

In the fast-paced world of web development, efficiency and clarity are paramount. As projects grow in complexity, so does the need for well-defined APIs. A clear API specification acts as a contract between the frontend and backend, ensuring seamless communication and a smoother development process. But creating these specifications can be a tedious and time-consuming task. Enter Vercel's v0, an AI-powered tool designed to streamline the development workflow. While v0 is known for its ability t

7 June 2025

Practice API Design-first in Apidog

Discover an easier way to build and use APIs