Motivation:
An amazing hypermedia story for the JSON API (module) will provide a ladder for Drupal-based decoupled applications to reach a higher level of sophistication. This next generation of decoupled Drupal applications will have rich and domain-specific feature sets that go far beyond the typical "website". These applications are already beginning to be built today, but they require close coupling to the backend because their possible interactions cannot be communicated via an API in a generic and standardized way.
We first allowed presentation to be decoupled from data storage, now we need operations on that data to be decoupled from its presentation.
Background:
Recently, @e0ipso shared this link: http://gtramontina.com/h-factors/ which highlights JSON APIs poor hypermedia support. At the same time, I've been thinking a lot about hypermedia recently.
We've not even begun to scratch the surface for what excellent hypermedia controls could do for APIs built with JSON API. We're exploring that space a bit in #2795279: [PP-4] [META] Revisions support, but it's still a fairly static implementation not extensible by the applications built on top of this module.
The only control we already provide is fixed across all instances of JSON API and enables only one, well-defined use case. Pagination.
Means:
The next level of support that we can provide is to allow developers to define and customize their own links between JSON API resources. Every API is built for a different purpose and every API needs to serve specific business logic. To drive client-server interactions specific to those needs, our responses need to contain links specific to every application.
This will take time and will need to happen incrementally. Let's let this issue serve as a hub for those issue that improve JSON API's hypermedia developer story. I propose we begin writing this story of hypermedia support by building the infrastructure below and dog-fooding that infrastructure by migrating the 2.x version of revision support to it.
Components:
Things which I'm thinking about, most of which will probably become issues in the issue queue, in no particular order:
- Work with JSON API maintainers to get better link support/Use a JSON API profile to add better link support. While http://gtramontina.com/h-factors/ shows that the spec doesn't have great hypermedia support, it doesn't preclude it. The only real impediment that the spec places on us is that it limits link cardinality to 1 (although I've seen the spec maintainers speak optimistically about loosening this restriction).
- A custom URI scheme for our use.
- A customizable set of link relation types, defined under our own URI scheme.
- A customizable set of link attributes, defined under our own URI scheme.
- A link relation type for "anchor" links. When present, these links would use a JSON Pointer to link to other members of the response document. See #2993654: Provide JSON Pointer as a link on a resource to ease matching with included items
- A link relation type for adding resource identifiers to a relationship.
- A link relation type for removing resource identifiers from a relationship.
- A link relation type for replacing a relationship's resource identifiers.
- A link relation type for path aliases.
- The ability for other modules to add and remove links from various JSON API objects (to include resource, relationship and error objects as well as the top-level links object).
- A reference JavaScript client that understands these implementations.
Goals:
As a taste of what these kinds of enhancements could enable, here's a complex, juicy tidbit:
{
"type": "product",
"id": "1",
"links": {
"drupal://jsonapi/extensions/commerce/links/relation-types/add-to-cart": {
"href": "https://example.com/order/4/relationships/items",
"drupal://jsonapi/links/target-attributes/relationship-arity": 3,
"drupal://jsonapi/links/target-attributes/operation": "drupal://jsonapi/links/target-attributes/operations/add-to-relationship",
}
}
}
- The
drupal://jsonapi/extensions/commerce/links/relation-types/add-to-cart
URI is in reference to a custom link relation type that defines the semantics of the link as a URL for adding an item to one's own cart. - The
drupal://jsonapi/links/attributes/operation
URI is in reference to a custom link attribute that defines the link as a URL upon which a specification-defined operation can be performed. - The
drupal://jsonapi/links/target-attributes/operations/add-to-relationship
URI is in reference to a defined HTTP method and request format for adding a resource identifier to a relationship. - The
drupal://jsonapi/links/target-attributes/relationship-arity
URI is in reference to a custom link attribute that communicates the highest arity of any duplicates for the context resource object.
Another example might be drupal://jsonapi/links/target-attributes/operations/add-to-collection/schema
, drupal://core/forms/metadata
and drupal://core/forms/validator
for a link defining the schema for an acceptable request document for an operation, a link defining metadata that describes how a form should be rendered by a frontend application, and a link from which a JavaScript file for validating a form submission could be obtained (yes, it's possible!).
"But those URIs are so ugly!"
JSON API v1.1 will likely contain the ability to assign "aliases" to these URIs. Using those aliases, my example could become:
{
"type": "product",
"id": "1",
"links": {
"add-to-cart": {
"href": "https://example.com/order/4/relationships/items",
"relationship-arity": 3,
"operation": "add-to-relationship",
}
}
}