JSON API Cheatsheet

written

The JSON API specification the following design goals:

  • Standardising the JSON schema (irrespective of the data you’re transmitting)
  • Minimising the number of client requests
  • Minimising the amount of data transmitted

Understanding how each is achieved is essential in effectively using its features.

The following is a reorganisation and summary of the full specification: https://jsonapi.org/

General requirements


Rquirement
Headers
Client and server both use Content-Type: application/vnd.api+json without any media type parameters
  • if the server receives a request with them, it returns 415 Unsupported Media Type

Client must also include application/vnd.api+json in  Accept header, if it uses that header
  • server responds with 406 Not Acceptable if all instances of the Mime Type in the Accept header have media type parameters
Query parameters
Query string must be URL encoded
  • e.g. [ and ] characters must be percent-encoded, per the requirements in RFC 3986.

Query parameters must adhere to the same constraints as member names below, with the additional requirement that they MUST contain at least one non a-z character
  • To preserve the ability of JSON:API to make additive additions to standard query parameters without conflicting with existing implementations
  • RECOMMENDED that a U+002D HYPHEN-MINUS, “-“, U+005F LOW LINE, “_”, or capital letter is used (e.g. camelCasing).

400 Bad Request:
  • Query parameter that does not follow the naming conventions and the server does not know how to process it as a query parameter from this specification
Request body
Can’t include any additional attributes beyond those specified - and if they appear the client and server must ignore them

A JSON object must be at the root of every request and response with data

Member (field) names:
  • Case-sensitive
  • Must have at least one character and start and end with globally allowed character (Can be used anywhere): 
    • U+0061 to U+007A, “a-z”
    • U+0041 to U+005A, “A-Z”
    • U+0030 to U+0039, “0-9”
    • U+0080 and above: non-ASCII Unicode and non URL safe characters (according to RFC 3986) are not recommended
  • Not allowed at the start or end:
    • * U+002D HYPHEN-MINUS, “-“
    • * U+005F LOW LINE, “_”
    • * U+0020 SPACE, “ “ (not recommended, not URL safe)
    • Full reference 

Design Goal: Standardised schema

Object shapes:

  • Top-level schema
  • Resource Object
  • Resource Identifier object
  • Linkage Object
  • Relationship Object

Consistent top level schema

The top-level schema of responses is the same, regardless of whether a collection, singular item or (possibly) no data is being returned

Client / Request

Nothing explicit; client needs to parse or deserialize the response to get it in a format that is easy to extract information from (JSON API is optimised for data transmission, not retrieval of information).

Server / Response


Required
Forbidden
Description
data
At least 1 of these must be defined
Can’t have data and errors at the same time
Document’s “primary data”: resource or collection of resources targeted by a request

Requests that target single resources:
  • Single resource object
  • Single resource identifier object, or
  • null

Requests that target resource collections:
  • Array of resource objects,
  • Array of resource identifier objects, or
  • Empty array
errors
Array of error objects
meta

meta object that contains non-standard meta-information.
links
No

Links object related to the primary data

{
  "links": {
    "self": "http://example.com/articles",
    "next": "http://example.com/articles?page[offset]=2",
    "last": "http://example.com/articles?page[offset]=10"
  },
  "data": [{
 
Each member of the links object must represent either:
  • String containing the link’s URL
  • Link object: can have members:
    • href: a string containing the link’s URL.
    • meta: a meta object containing non-standard meta-information about the link.

Indicating how many of an association is available:

"links": {
  "related": {
    "meta": {
      "count": 10
    }
  }
}


Required
Description
self
No
Link that generated the current response document.
related
No
Related resource link when the primary data represents a resource relationship.
  • Access to resource objects linked in a relationship
pagination links
No
Links for the primary data.
included
No.
When data is not present
Array of resource objects that are either:
  • Related to the primary data and/or
  • Related to each other
jsonapi
No

Object describing the server’s implementation

If the version member is not present, clients should assume the server implements at least version 1.0 of the specification.

Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
{
  "data": [{
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "JSON:API paints my bikeshed!"
    },
    "links": {
      "self": "http://example.com/articles/1"
    },
    "relationships": {
      "author": {
        "links": {
          "self": "http://example.com/articles/1/relationships/author",
          "related": "http://example.com/articles/1/author"
        },
        "data": { "type": "people", "id": "9" }
      },
      "comments": {
        "links": {
          "self": "http://example.com/articles/1/relationships/comments",
          "related": "http://example.com/articles/1/comments"
        },
        "data": [
          { "type": "comments", "id": "5" },
          { "type": "comments", "id": "12" }
        ]
      }
    }
  }],
  "included": [{
    "type": "people",
    "id": "9",
    "attributes": {
      "first-name": "Dan",
      "last-name": "Gebhardt",
      "twitter": "dgeb"
    },
    "links": {
      "self": "http://example.com/people/9"
    }
  }, {
    "type": "comments",
    "id": "5",
    "attributes": {
      "body": "First!"
    },
    "relationships": {
      "author": {
        "data": { "type": "people", "id": "2" }
      }
    },
    "links": {
      "self": "http://example.com/comments/5"
    }
  }, {
    "type": "comments",
    "id": "12",
    "attributes": {
      "body": "I like XML better"
    },
    "relationships": {
      "author": {
        "data": { "type": "people", "id": "9" }
      }
    },
    "links": {
      "self": "http://example.com/comments/12"
    }
  }]
}

Consistent data objects

Client / Request

Nothing explicit; client needs to parse or deserialize the standard object shapes.

Server / Response

The schema comprises of two object types:

  • Resource objects: Contain the full list of attributes to represent a resource
  • Resource identifier objects: Contain only the necessary information to identify a resource (for linking or requesting the resource object later on)

Resource object vs resource identifier object:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Resource object:
{
  "data": {
    "type": "articles",
    "id": "1",
    "attributes": {
      // ... this article's attributes
    },
    "relationships": {
      // ... this article's relationships
    }
  }
}

// Resource identifier object:
{
  "data": {
    "type": "articles",
    "id": "1"
  }
}

Resource object


Required
Description
id
Yes - unless new object coming from client
Must be strings that together uniquely resolve to a single resource

type 
  • used to describe resource objects that share common attributes and relationships
  • Can be either plural or singular (but must be used consistently)
type
Yes
attributes
No
  • Information about the resource object
  • Known as the resource’s fields
  • Any object that constitutes or is contained in an attribute MUST NOT contain a relationships or links member
  • has-one foreign keys SHOULD NOT appear as attributes
relationships
No
Relationships (to-one or to-many) between the resource and other JSON:API resources.
links
No
Links related to the resource
meta
No
meta object containing non-standard meta-information about a resource that can not be represented as an attribute or relationship

Hyperlinked media: Standard way of navigating between data

Client / Request

Nothing explicit; client needs to find and use the most appropriate link

Server / Response

links: Can include links to navigate pages, to reload self or to fetch associated data

  • Provides easy navigation by including URLs for each request the client may wish to make next, in the current response

Abstract relationships: Standard way of representing all relationships, regardless of implementation

Client / Request

Nothing explicit; client needs deserialize the response and match up included data with its parent using the relationships

Server / Response

data.relationships: Abstracts the details of how items are associated (join tables, foreign keys, etc) and just returns the associated data * Only contains primary keys and data types - for the other attributes, you need to (request and) match up with the data in the included

Relationships are treated as their own entity, allowing endpoints for interacting on the relationship rather than the related resource

Example: author relationship includes

  • Link for the relationship itself (allows the client to change the related author directly)
  • Related resource link to fetch the resource objects
  • Linkage information.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// ...
{
  "type": "articles",
  "id": "1",
  "attributes": {
    "title": "Rails is Omakase"
  },
  "relationships": {
    "author": {
      "links": {
        "self": "http://example.com/articles/1/relationships/author",
        "related": "http://example.com/articles/1/author"
      },
      "data": { "type": "people", "id": "9" }
    }
  },
  "links": {
    "self": "http://example.com/articles/1"
  }
}
// ...

Relationships object schema


Required
Description
links
At least one of these must be defined

Links object
Attribute
Required
Description
self
At least one of these is required
Link for the relationship (join table) - allows the client to directly manipulate the relationship.
  • For example, removing an author through an article’s relationship URL would disconnect the person from the article without deleting the people resource itself. 
related
Link to related resource 
  • When fetched, the related resource object(s) are returned as the response’s primary data.
  • E.g: An article’s comments relationship could specify a link that returns a collection of comment resource objects when retrieved through a GET request

If present link MUST reference a valid URL, even if the relationship isn’t currently associated with any target resources
  • MUST NOT change because its relationship’s content changes
pagination links

To-many relationship MAY also contain pagination links
Paginate the relationship data, not the related resources.
data
Resource linkage
  • Allows a client to link together all of the included resource objects without having to GET any URLs via links.
  • to-one relationships: null or a single resource identifier object
  • to-many relationships: empty array or array of resource identifier objects

Spec doesn’t impart meaning about order of array, although implementations may
  • May represent ordered or unordered relationships, and both types can be mixed in one response object.
meta
Non-standard meta-information about the relationship

Standard error reporting

Client / Request

Client needs to deserialize the response and handle the errors

Server / Response

errors: Generalised error reporting that can account for one or more errors occurring

Error schema:

  • id Unique identifier for this particular occurrence of the problem
  • links Links object containing the following members
  • about: a link that leads to further details about this particular occurrence of the problem.
  • status HTTP status code applicable to this problem, expressed as a string value.
  • code application-specific error code, expressed as a string value
  • title short, human-readable summary of the problem that SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization.
  • detail human-readable explanation specific to this occurrence of the problem. Like title, this field’s value can be localized.
  • source Object containing references to the source of the error, optionally including any of the following members:
    • pointer: a JSON Pointer [RFC6901] to the associated entity in the request document [e.g. “/data” for a primary data object, or “/data/attributes/title” for a specific attribute].
    • parameter: a string indicating which URI query parameter caused the error.
  • meta meta object containing non-standard meta-information about the error

Server can either stop processing as soon as a problem is encountered, or continue and encounter multiple problems

  • The most generally applicable HTTP error code should be used in the response

Design Goal: Minimise number of requests

Compound Documents: Including related data client needs

Client / Request

include query parameter: Comma-separated list of relationship paths (dot-separated list of relationship names)

1
2
GET /articles/1?include=comments.author HTTP/1.1
Accept: application/vnd.api+json

Client is required to re-assemble the connections using the primary fields and types in relationships and plucking them out of the included array * Just a flat list - have to match up where they should be nested by finding the matching resource identifier object

Server / Response

Adds a flat, normalised (duplicates removed) array of associated resources in the included attribute

  • Response is called a “compound document” (consists of more than just the primary resource requested)
  • Note: query param is named include while attribute is named included

Server may return resources related to the primary data by default and may also support an include request parameter to allow the client to customize which related resources should be returned

  • Server must remove all default included and only use those specified, if the client is using the query parameter

Because compound documents require full linkage (every included (full) resource object must be referenced by a resource identifier object somewhere else in the document), intermediate resources in a multi-part path must be returned along with the leaf nodes.

  • Exception: when relationship fields that would otherwise contain linkage data are excluded via sparse fieldsets (see below).
  • Server may choose to expose a deeply nested relationship as a direct relationship with an alias such as comment-authors for comments.author
  • would allow a client to request /articles/1?include=comment-authors instead of /articles/1?include=comments.author
  • Server can still provide full linkage in compound documents without including potentially unwanted intermediate resources.

Applies to all request types: a server could support the inclusion of related resources along with a POST request to create a resource or relationship

400 Bad Request
  • Request uses the include parameter for an endpoint that does not support it
  • Server is unable to identify a relationship path
  • Server does not support inclusion of resources from a path

Metadata: Including summary and other metadata

Client / Request

Included by default - up to the server to implement.

Server / Response

meta attribute for things like counts and modified dates, so don’t have to request all results to generate aggregate or summary information

Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
  "meta": {
    "copyright": "Copyright 2015 Example Corp.",
    "authors": [
      "Yehuda Katz",
      "Steve Klabnik",
      "Dan Gebhardt",
      "Tyler Kellen"
    ]
  },
  "data": {
    // ...
  }
}

Design Goal: Minimise amount of data transmitted

Query parameters quick reference

Sorting
?sort=age,-name
  • Sort precedence must match order fields are specified in
  • Default order is ascending, - makes it descending
Filtering
?filter[foo]=bar&filter[baz]=bla
  • Agnostic to filter algorithm used (exact matches, contains, etc)
Pagination
?page[number]=
  • Agnostic to paging algorithm used (pages, offsets, etc)
Including related resources
?include=a.b,a.c
Sparse fieldsets
?fields[a]=b,c&fields[d]=e

Filtering: Restricting results based on criteria

Client / Request

filter query parameter is reserved for filtering data, but doesn’t tell you how to use it: (implementation agnostic, so can use any filter implementation/algorithm)

  • Usually involves specifying multiple filters using the square brackets syntax: filter[name]=foo&filter[age]=21

Server / Response

data:

  • Collections: Filters items in the primary document
  • Items: Filters the scope for looking up the item (may result in 404 Not Found)

Sorting: Ordering results

Client / Request

sort query parameter is used for filtering

  • Recommended dot-separated sort fields be used: E.g. author.name could be used to request that the primary data be sorted based upon the name attribute of the author relationship
  • However, fields do not necessarily need to correspond to resource attribute and association names

Sort fields are applied in the order specified

1
2
GET /people?sort=age,name HTTP/1.1
Accept: application/vnd.api+json

Sort fields are ascending unless it is prefixed with a minus

1
2
GET /articles?sort=-created,title HTTP/1.1
Accept: application/vnd.api+json

Server / Response

data:

  • Collections: Changes the order of items in the primary document
  • Items: No effect

Server may apply default sorting rules to top-level data if request parameter sort is not specified.

400 Bad Request
Server does not support sorting as specified in the query parameter sort

Pagination: Truncating data into pages

Client / Request

page query parameter is reserved for pagination, but doesn’t tell you how to use it: (implementation agnostic, so can use any pagination strategy: page-based, offset-based, cursor-based)

  • Eg. page[number] and page[size], an offset-based strategy might use page[offset] and page[limit], while a cursor-based strategy might use page[cursor]

Server / Response

data:

  • Collections: Truncates the full set of results in the primary document into pages
  • Items: No effect

meta: Not dictated, but there are examples of it being used to store the total number of results

included: Server may also paginate included resources

links: If they server does provide pagination, need to include pagination links: first, last, prev, next

  • Can be omitted or be null if they’re unavailable
  • Placed at the top level or in the included resource they relate to

Sparse fieldsets: Selectively including data client needs

Client / Request

fields query parameter used for specifying a whitelist of attributes to include by specifying a fields[TYPE] parameter.

  • Comma separated list
  • Empty value indicates that no fields should be returned.

Example:

1
2
GET /articles?include=author&fields[articles]=title,body&fields[people]=name HTTP/1.1
Accept: application/vnd.api+json

Server / Response

If a client uses sparse fieldsets, server must not send back any others

  • If not used, server may send all fields, a subset of fields, or no fields for that resource type.

included / relationships: Lifts the requirement of full linkage if the relationship fields that would otherwise contain linkage data are excluded via sparse fieldsets.

Working with primary resources (CRUD)

Viewing a resource

Server / Response

Server must actually implement any routes mentioned in self and related

The data attribute of a response must be a (possible empty) array of resource objects or resource identifier objects for collections, and a resource object or null for a singular item.

Response

200 OK
Successful request to fetch
404 Not Found
Request to fetch a single resource that does not exist
  • Use a 200 OK response with null as the primary data if the requested URL is one that might correspond to a single resource, but doesn’t currently
Other responses
Can be used, including setting the errors attribute

General (For Creating, Updating and Destroying)

Request must completely succeed or fail (in a single “transaction”). No partial updates are allowed.

If the client somehow does not have the most up-to-date and complete set of values, the server must respond with the full document again

Examples:

  • If using client-generated ids which are ignored and replaced with server generated ones (client needs to be told actual ids used)
  • If not using client-generated ids (client needs to be told ids used)
  • If updating or creating some attributes, which cause others to be updated or have defaults set (client needs to be told full set of new values)

If the server responds with 204 No Content, client should assume it already has the complete and most up-to-date values for a resource

Creating a resource

Client / Request

Server may accept a client-generated ID along with a request to create a resource, but they must be a universally unique identifier (ideally a properly generated and formatted UUID as described in RFC 4122)

Server / Response

Response

201 Created
Request did not include a Client-Generated ID then it must use 201 Created
  • Also should include a Location header identifying the location of the newly created resource. (must match self link if they’re both provided)
  • Must respond with a document that contains the primary resource created
204 No Content
Request did include a Client-Generated ID (and the server used it unaltered): Can use 201 Created with document or 204 No Content with no document (below)
  • Client should consider the resource object sent in the request to be accepted by the server
202 Accepted
Request to create a resource has been accepted for processing, but the processing has not been completed by the time the server responds
403 Forbidden
Unsupported request to create a resource:
  • Including if the server doesn’t support client-generated IDs
404 Not Found
Processing a request that references a related resource that does not exist.
409 Conflict
Either:
  • Request to create a resource with a client-generated ID that already exists
  • When type is not among the type(s) that constitute the collection represented by the endpoint

server SHOULD include error details and provide enough information to recognize the source of the conflict.
Other responses
Can be used, including setting the errors attribute

Updating a resource

Client / Request

Can include all or none of the resource’s attributes in an update request Can include some or all of a resource’s relationships

Server / Response

Server interprets any missing attributes or relationships as if they were included with their current values (and NOT null or undefined)

  • If a relationship is provided, the value will be replaced with the value specified in this member.

Example: Completely replace tags for an article

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
  "data": {
    "type": "articles",
    "id": "1",
    "relationships": {
      "tags": {
        "data": [
          { "type": "tags", "id": "2" },
          { "type": "tags", "id": "3" }
        ]
      }
    }
  }
}

200 OK
Server accepts an update but also changes the resource(s) in ways other than those specified by the request
  • E.g., updating the updatetAt attribute or a computed sha
  • Response document must include a representation of the updated resource(s) as if a GET request was made to the request URL (i.e. include all the attributes - not just those changed)

If an update is successful, the client’s current fields remain up to date, and the server responds only with top-level meta data. 
  • If this is the case, must not include a representation of the updated resource(s).
202 Accepted
Request has been accepted for processing, but the processing has not been completed by the time the server responds
204 No Content
Update is successful and the server doesn’t update any fields besides those provided
  • Server responds with no response document
403 Forbidden
Unsupported request to update a resource or relationship.

Particularly, since full replacement may be a dangerous operation, a server may choose to disallow it
  • May reject an attempt to do a full replacement of a to-many relationship. (Server must reject the entire update)
  • May reject full replacement if it has not provided the client with the full list of associated objects, and does not want to allow deletion of records the client has not seen.
404 Not Found
Either:
  • Request to modify a resource that does not exist.
  • Request that references a related resource that does not exist.
409 Conflict
Either:
  • Request to update a resource if that update would violate other server-enforced constraints (such as a uniqueness constraint on a property other than id).
  • Request in which the resource object’s type and id do not match the server’s endpoint.

Server should include error details and provide enough information to recognise the source of the conflict.
Other responses
Can be used, including setting the errors attribute

Destroying a resource

1
2
DELETE /photos/1 HTTP/1.1
Accept: application/vnd.api+json

Doesn’t appear to need the resource id or type in the body of the request.

202 Accepted
Request has been accepted for processing, but the processing has not been completed by the time the server responds,
204 No Content
Deletion request is successful and no content is returned.
200 OK
Deletion request is successful and the server responds with only top-level meta data.
404 Not Found
Deletion request fails due to the resource not existing.

Working with relationships directly

JSON API treats relationships as their own singular resource, providing APIs for interacting with them directly (regardless of their implementation):

  • Each relationship object can contain a link for interacting with the relationship directly
  • The behaviour of requests to that URL depend on the HTTP method you use
Operation
HTTP Request type
View
GET
Add to
POST
Replace
PATCH
Remove from
DELETE

Viewing Relationships

Returns the relationship object with a data value that is collection or singular resource, depending on whether it’s a to-one or to-many relationship

200 OK
Successful request to fetch
404 Not Found
Fetch a relationship link URL that does not exist.
  • Can happen when the parent resource of the relationship does not exist
  • If a relationship link URL exists but the relationship is empty, then 200 OK MUST be returned
Other responses
Can be used, including setting the errors attribute

Updating Relationships

Has the same endpoint shape, regardless of implementation semantics (foreign keys, join tables etc)

Server can choose to delete the underlying resource if a relationship is deleted (as a garbage collection measure).

Update a To-One relationship: Only PATCH is supported - i.e. you’re updating it whether the relation currently exists or not

Client / Request

Client include a top-level member named data containing one of:

  • A resource identifier object corresponding to the new related resource.
  • null, to remove the relationship.
Swap a relationship
1
2
3
4
5
PATCH /articles/1/relationships/author HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{ "data": { "type": "people", "id": "12" }}
Removing a relationship
1
2
3
4
5
PATCH /articles/1/relationships/author HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{ "data": null}

Update a To-Many relationship: PATCH, POST and DELETE are supported

Client / Request

Body must contain a data member whose value is an empty array or an array of resource identifier objects

POST request: Adding items to a relation

Server / Response

Adds the specified members to the relationship unless they are already present

  • If a given type and id is already in the relationship, the server does not add it again

If all of the specified resources can be added to, or are already present in, the relationship then the server returns a successful response.

  • Ensures a request is successful if the server’s state matches the requested state
  • Helps avoid pointless race conditions caused by multiple clients making the same changes to a relationship.
1
{ "data": [ { "type": "comments", "id": "123" } ]}
PATCH Request: Replaces all existing items in the relation

Server / Response

Either:

  • Completely replace every member of the relationship
  • Return an appropriate error response if some resources can not be found or accessed
  • Return 403 Forbidden
403 Forbidden
If full replacement of the association is not permitted
DELETE Request: Remove items from a relation

Server / Response

Removes the specified members from the relationship or return a 403 Forbidden response

If all of the specified resources are able to be removed from, or are already missing from, the relationship then server returns a successful response

202 Accepted
Relationship update request has been accepted for processing, but the processing has not been completed by the time the server responds
204 No Content
update is successful and the representation of the resource in the request matches the result
  • POST request sent to a URL from a to-many relationship link when that relationship already exists.
  • DELETE request sent to a URL from a to-many relationship link when that relationship does not exist.
200 OK
Server accepts an update but also changes the targeted relationship(s) in other ways than those specified by the request
  • Response document MUST include a representation of the updated relationship(s).

Server MUST return a 200 OK status code if an update is successful, the client’s current data remain up to date, and the server responds only with top-level meta data. 
  • In this case the server MUST NOT include a representation of the updated relationship(s
403 Forbidden
Unsupported request to update a relationship.
Other responses
Can be used, including setting the errors attribute

Comments