1. What is JSON API?
According to its homepage, JSON API is “a specification for building APIs in JSON”. More specifically, it is the combination of a format specification for JSON payloads representing (collections of) resources1, and a set of rules to interact with (i.e. create/read/update/delete) those resources.
A resource in this context is an object with a
type, and an
id (the pair identifying uniquely the corresponding resource), and optionally some fields, which could be either attributes (arbitrary objects), or relationships (towards zero, one, or several other resources).
Resources could be, for instance,
1.1. Your resources form a graph
A graph is a simple mathematical structure that consists of a set of vertices, some of which are pairwise related by edges (so, formally, it is a set
V along with a subset
In this context, your resources form the set
V of (labelled) vertices of a graph whose (directed, labelled) edges are the relationships between resources.
More specifically, a vertex is labelled “primarily” by the
id of the resource, and “secondarily” by its attributes.
Moreover, this graph has the property that the
types of resources form a partition of the vertices, and that the pair
(type, id) of a resource identifies it uniquely.
1.2. JSON API defines a representation for subgraphs of resources
A subgraph of a graph is a subset of the vertices of the graph, along with some (not necessarily all) of the edges attached to those vertices3.
As outlined in the introduction, JSON API defines a format for representing collections of resources. More specifically, it defines a format for representing a subgraph of your resource graph4 (i.e. some resources, and some (directly or indirectly) related resources).
The way this subgraph is represented is via its adjacency lists: each resource of the subgraph appears exactly once, along with its edges (i.e. its relationships towards other resources in the subgraph).
This representation is nice because it avoids headaches when representing cycles (for instance when user
A follows user
B who in turn follows user
A), and avoids redundant information.
1.3. JSON API defines rules to add/modify/delete vertices/edges
The spec also defines rules for interacting with endpoints representing resources. The defined operations are (roughly):
POST /users: create a new vertex in the graph, labelled by the type
users, with edges towards already existing vertices;
PATCH /users/5: modify some secondary labels (i.e. resource attributes) of a given vertex, along with replacing some edge sets incident to that vertex (for instance replacing the set of “posts” of that
userwith a new set of (existing) “posts”);
DELETE /users/5: delete a given vertex, along with all its incident edges;
PATCH /users/5/relationships/posts: replace the set of edges labelled “posts” with the given set of edges;
POST /users/5/relationships/posts: add one edge to the set of edges labelled “posts” (incident to that
DELETE /users/5/relationships/posts: delete the specified edges (that are incident to the given user).
2. Limitations of JSON API
2.1. JSON API does not define rules for modifying multiple edge sets
A first limitation that appears is the impossibility to modify multiple edge sets (i.e. multiple to-many relationships) of a single vertex in one operation, except if fully replacing those relationships.
To solve this limitation, the following part of the spec:
could be modified into:
As an example, the following request would be valid:
whereas it would have taken either one non-practical request by full replacements, or four requests (one for updating the title, one for adding a tag, one for removing a tag, and one for removing a comment).
2.2. JSON API does not define rules to add subgraphs
An other limitation that appears, is the impossibility to add a whole subgraph to the resources graph. As described above, vertices can only be added one by one, and newly added vertices can only have edges pointing towards existing vertices.
Three cases could be considered here:
2.2.a) Adding a collection of independent vertices
The spec could be extended to support creation of multiple (unrelated) resources in one request, in a fairly straightforward way, by allowing the following:
2.2.b) Adding one (or more) independent trees
The spec could also easily be extended to support creation of (one or more, as in the previous case) trees (i.e. creating one resource, related to other new resources (possibly related to other new resources, etc.) - the key being that none of the new resources should be related to any other resource except their parent). One possible syntax for this is to simply embed the new resources in their parent’s definition. This is possible because the graph is actually a tree, so it has no cycles.
As an example:
which would result in one post, one comment, and three tags being created - two tags being attached to the comment, itself attached to the post, and one tag attached to the post directly.
2.2.c) Adding an arbitrary subgraph
The spec could be extended to support addition of one or more (almost) arbitrary subgraphs. The main problems here are
- multiple references to a newly created resource, and
The natural way to solve 2. is to represent the graph by its adjacencies, in order to be consistent with the rest of the spec. The issue is that newly created resources do not have an
id yet, so cannot be referenced. The obvious solution is to give them a temporary
id, the only purpose of which would be to identify yet-to-be-created resources inside the document. Such temporary
ids could have a special format, like starting with a reserved symbol. Those newly created secondary resources would then fall under some
added_data toplevel member of the document.
2.2.d) Modifying a subgraph
Finally, it would be possible to combine the solutions outlined in 2.1 and 2.2.c) in order to provide a way to modify a resource, while adding new secondary resources, updating some, deleting some, and updating the base resource’s to-many relationships without replacing them. In order to do that, we could introduce, as in 2.2.c), an
added_data (along with a
removed_data and an
updated_data) toplevel members, combined with temporary
Not exactly the same as REST resources. ↩
It is worth noting at this point that a resource is an abstract entity that is not necessarily the direct representation of an object in your database. ↩
Note: a subgraph is clearly a graph itself. ↩
Not any subgraph, only those that are the union of subgraphs obtained from a collection of resources of same type, by adding all vertices reachable by a prefix of a collection of edge-labelled paths. ↩