JSON:API primer


At work we were working on a new REST API. After some investigation, we came across json:api.

json:api is a specification for building APIs in Json

It lays out standard conventions for usual concerns when building a REST API like-

  • payload structure for single resources and relationships
  • links
  • pagination
  • partial loading of a resource
  • loading of multiple related resources
  • error formats

With these shared conventions the API design feels more coherent and ultimately more usable for clients.

Also the format is readable JSON even if you do not know about json:api. Here is an example (with invalid json comments)

{
  "data": {                                 // primary data object
    "type": "blog",                          // type of the single resource object
    "id": "1",                               // id of the single resource object
    "attributes": {                          // attributes
      "title": "JSON:API quick starter",     // string based attribute
      "created": "2018-10-05T00:00:00+00:00"
    },
    "relationships": {                       // relationships
      "author": {                            // named relationship
        "links": {
          "self": "/blogs/1/author",         // relationship link between blog and peeps
          "related": "/peeps/1"              // independent object
        }
      },
      "comments": {                          // other named relationsh
        "links": {
          "self": "/blogs/1/comments"        // relationship link to dependent objects
        }
      }
    }
  }
}

Specification quick starter

The complete specification for v1.0 of the format is available online. In this blog I’ll extract some parts which should simplify the spec (but is also incomplete and hence wrong).

Content Negotiation

Content-Type header for requests and response should be

Content-Type: application/vnd.api+json

Document Structure

Top Level

A JSON object MUST be at the root of every JSON API request and response containing data.

A document can contain the following top-level members:

  • data: the document’s “primary data”, or
  • errors: an array of error objects
  • links: (optional) a links object related to the primary data.

One of data or errors is required.

The top-level links object MAY contain the following members:

  • self: the link that generated the current response document.
  • related: a related resource link when the primary data represents a resource relationship.
  • pagination links for the primary data.

Primary data MUST be either:

  • A single resource object, a single resource identifier object, or null, for requests that target single resources
  • An array of resource objects, an array of resource identifier objects, or an empty array ([]), for requests that target resource collections

Resource Objects

“Resource objects” appear in a JSON API document to represent resources.

A resource object MUST contain at least the following top-level members:

  • id: string (except when client creates and resource and id is generated on server)
  • type: string. The type member is used to describe resource objects that share common attributes and relationships.
  • attributes: an attributes object representing some of the resource’s data.
  • relationships: a relationships object describing relationships between the resource and other JSON API resources.
  • links: a links object containing links related to the resource.

Identification - Within a given API, each resource object’s type and id pair MUST identify a single, unique resource.

Attributes

The value of the attributes key MUST be an object (an “attributes object”). Members of the attributes object (“attributes”) represent information about the resource object in which it’s defined.

Attributes may contain any valid JSON value.

Relationships

The value of the relationships key MUST be an object (a “relationships object”). Members of the relationships object (“relationships”) represent references from the resource object in which it’s defined to other resource objects.

Relationships may be to-one or to-many.

A “relationship object” MUST contain at least one of the following:

  • links: a links object containing at least one of the following:
    • self: A link for the relationship itself (a “relationship link”). This URL allows the client to directly manipulate the relationship. For example, it would allow a client to remove an author from a post without deleting the people resource itself.
    • related: URL for the related resource(s). When fetched, it returns the related resource object(s) as the response’s primary data.

A relationship object that represents a to-many relationship MAY also contain pagination links under the links member, as described below. Any pagination links in a relationship object MUST paginate the relationship data, not the related resources.

Fetching Data

Any links returned must be GET-able. Standard HTTP status codes should be returned and additional information can be sent in error objects.

Pagination

JSON API is agnostic about the pagination strategy used by a server. The page query parameter can be used as a basis for pagination like

  • page-based - page[number] and page[size]
  • offset-based - page[offset] and page[limit]
  • cursor-based - page[cursor]

The following keys MUST be used for pagination links:

  • first: the first page of data
  • last: the last page of data
  • prev: the previous page of data
  • next: the next page of data

The pagination query parameters have [] and require URL encoding to be used by clients curl uses un-encoded [ ] as part of the globbing feature.

This ^ is a big reason for me to deviate from json:api and hence question the standard.

Creating, Updating and Deleting

A request MUST completely succeed or fail (in a single “transaction”). No partial updates are allowed. The type member is required in every resource object.

  • Creation follows the standard REST POST style. Relationships can also be added during the POST by a data object.
  • Updating is done via PATCH on either the attributes or relationships. The relationship link MUST support PATH, POST, DELETE for to-many relationships.
  • Deletion is via the DELETE method

Error object

An error object may have the following members

  • id: a unique identifier for this particular occurrence of the problem.
  • links: a links object containing the following members:
    • about: a link that leads to further details about this particular occurrence of the problem.
  • status: the HTTP status code applicable to this problem, expressed as a string value.
  • code: an application-specific error code, expressed as a string value.
  • title: a short, human-readable summary of the problem that SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization.
  • detail: a human-readable explanation specific to this occurrence of the problem. Like title, this field’s value can be localized

Also in the specification

  • Meta information
  • Data within a relationship
  • Compound document information
  • Embedding/Including additional resources
  • Sparse fieldsets
  • Sorting
  • Filtering