Metatype JSON API interop
This package provides facilities for interop with JSON API format using metatype.
Motivation
The JSON API specification defines an application-level protocol for communicating about basic data operations. The transmission format represents a general “linked-data” model that is suitable for use with both relational and graph databases.
JSON API treats relationships as a first-class concept. It further distinguishes “to-one” and “to-many” relationships. To marshal between JSON API format and runtime objects thus requires knowledge of these semantics. Yet these distinctions are not necessarily known by the host objects representing the resources. Metatype definitions can be used to supply this knowledge at the application level.
Features
The package provides functions for:
-
outgoing: mapping record-type objects to JSON API documents
-
incoming : mapping JSON API documents and resources to record-type objects
The “incoming” and “outgoing” terminology adopts the server's point of view, but these distinctions are only for internal organization. The mappings can be used by JSON API clients as well. (This suggests there may be better names.)
Static types
This package uses TypeScript definitions from the jsonapi-typescript package.
While it is technically possible to provide more refined type mappings using metatype information, it is assumed that the conversions provided here will be used primarily at system boundaries and that, e.g. call-site construction of specific record types would provide no additional benefit.
type
Optionality of One of the open design issues in this package (and the underlying metatype
package) is the use of type
in resource identifiers.
According to the definition of “Resource Identifier Objects” in the JSON:API spec,
A “resource identifier object” MUST contain
type
andid
members.
Although the rationale is not documented as such, this requirement is apparently based on the assumption of a relational data model in which primary key values are type-local, making it necessary to use type identifiers as “namespaces” for entities. (In practice, the types themselves also use names local to the system.)
A primary aim of the metatype
packages is to facilitate interop between linked
data models (particularly RDF) and common representation formats.
In the RDF data model, all entities use IRI's for names, meaning that an id
alone is sufficient to identify a resource.
Moreover, rather than having exactly one type, an RDF resource can have zero or more types.
These mismatches are a source of friction when interoperating between JSON:API and an RDF-based data store.
Currently, this package (along with metatype
generally) sacrifices JSON:API
spec compliance by making type
optional in most places where it would
otherwise be required by JSON:API.
This is not a good solution, particularly since it means that strengthening spec-compliance would be a breaking change in some contexts.
Contextual type
In some situations, the type of a document may be implied by its context.
The JSON:API notes this in the section on CRUD operations:
Note: The
type
member is required in every resource object throughout requests and responses in JSON:API. There are some cases, such as whenPOST
ing to an endpoint representing heterogeneous data, when thetype
could not be inferred from the endpoint. However, picking and choosing when it is required would be confusing; it would be hard to remember when it was required and when it was not. Therefore, to improve consistency and minimize confusion,type
is always required.
As is implied here, there are cases—such as an endpoint representing homogeneous
data—where type
can be inferred from context.
For example, a JSON:API endpoint may allow part of its URL to indicate a type. Endpoints like the following are indeed very common:
https://example.com/type/Plant
GET
requests to this endpoint may list all resources of type Plant
.
Questions arise, however, if such an endpoint is to accept POST
requests.
-
Implementations may want to relax the rule requiring
type
on the input. This creates an intermedate processing step, about which see below. -
POST
requests in JSON:API can specify atype
. What if the specified type differs from the one implied by the context?
Conclusions so far
This is a boundary issue, unless we plan to redefine JSON:API resource object in a way that conflicts with the spec. JSON:API types and processing routines are indeed simplified by requiring type. In order to process JSON:API documents, they must be put into the expected form at some point.
Even so, there are situations where you expect a shape that is a JSON:API
document except that type
is optional. While such a type would not represent
anything described by the official spec, it may still arise during intermediate
processing in implementations where the rule is relaxed.