This document (version 0.1) defines a hook service according to the terms set out in the core specification.
Under the hook service, a block can invite embedding application to take over the rendering of an element within the block (the hook), allowing embedding applications to provide users with application-specific views of specific data types without the block needing to know about them.
The service is designed to meet the following aims:
The service meets these aims by allowing blocks to delegate visualizing and editing functionality upwards to the embedding application.
The hook service is dependent on the graph service, as it relies on the existence of entities – use of the graph service is a prerequisite for use of the hook service.
Hook: an injection point blocks provide to embedding applications to allow them to optionally render or modify already rendered views associated with a property for an entity.
View: the elements the embedding application renders inside the hook (and associated functionality). A view may display read-only data or present editable data at the application’s discretion.
Blocks initiate hooks by asking embedding applications to take over a DOM node (the hook) and render the application’s preferred view of data of a specified type.
To request a view is rendered into a hook, a block MUST send a hook
message. The value for hookId
MUST be null
when a block first establishes a hook.
If the embedding application supports the requested hook type:
hook
message:
type
node
or by attaching elements within itpath
on the entity associated with the specified entityId
hookResponse
message specifying a hookId
to identify the hook with in futureIf the embedding application does not support the requested hook type, it MUST respond with an error with a code of NOT_IMPLEMENTED
.
If any of the required data is missing from the hook
message, the embedding application MUST respond with an error with a code of INVALID_INPUT
.
Blocks may request that a hook is updated or removed.
On removal, embedding applications should cease any further activity in relation to the DOM node.
Updating is a convenience for blocks to change aspects of a hook without having to send a message to destroy a hook followed by a message to establish a hook with the new parameters.
Removing hooks
Once a hook has been established, blocks MAY request their removal by sending a hook
message with the following values:
hookId
: the id that was provided by the embedding application in the original hookResponse
messagenode
: null
entityId
, type
and path
: whatever values are currently applied to the hookIf an embedding application receives a hook
message with a value of null
for node
, it MUST cease any activity and remove any subscriptions in relation to the node
(e.g. it should not make further modifications to the node, and should remove event listeners).
Updating hooks
Once a hook has been established, blocks MAY vary its implementation by sending a hook
message with the hookId
provided in the original response, and the following values as desired:
type
to request that the type of view is changedpath
to request that the data used to populate the view is retrieved from and persisted to the path
on the specified entityentityId
to request that data from a new entity is usednode
to request that the view is rendered at a different place in the DOMWhen a hook
message is sent with a hookId
corresponding to a previously-established hook, embedding applications MUST update the view for that hook according to the new parameters.
If such a message specifies a new node
, the embedding application MUST follow the process for removing hooks for the previous node
(e.g. cease modification of and remove subscriptions from that node).
Hooks provide a way for applications to render their preferred view of data from a specific property belonging to a specific entity.
Applications should still provide the relevant data to the block, and should ensure that its representation matches that specified in the block’s schema (which may be different to how the application is using it in the hook).
Embedding applications MUST use any value under the specified path
in the properties in the specified entity to initialise the view they render.
As per the graph specification, embedding applications MUST provide a valid value for the specified path
for any entity when sending data to the block. This may involve a different representation of the data than the application stores. For example, if an entity type specifies type: "string"
for a property, and the application has stored data on that property as complex rich text objects (owing to previous or current use of the hook service for that property, or for some reason), the application MUST translate those rich text objects into a simple string when sending the property to the block, in order for the data send to comply with the entity schema.
The type of a hook request indicates the type of data the block is requesting a view to be rendered for. The specification permits any string, but we expect particular use to be made of text
, and to a lesser extent image
and video
.
As an example, take text
. The data structure for formatted text may be bespoke to the embedding application, and impossible for the block to predictably parse or generate. The expected text editing experience may involve custom formatting controls, or special inline actions or commands. By using the hook service to inject its own rich text editing input, an embedding application can provide the desired experience and functionality.
The type
of a hook MUST be a string.
Embedding applications MUST render an appropriate view for the specified type, if they support it (e.g. a type of text
should be rendered as something that appears to the user as text, however the application chooses to present it).
There are only two messages in the hook service: the hook
request from the block, and the hookResponse
acknowledgement from the embedding application.
The messages available for exchange in the hook service are defined in the service's JSON definition and are also listed below for ease of reference.
hook[block]
hookResponse[embedder]
hook
source
: blockdata
: object
property | type | required | description |
---|---|---|---|
node | object | null | yes | The DOM node the embedding application will render a view into, or modifying an already rendered view. If null, the view should be destroyed. |
type | yes | The type of view for the hook. Technically permits any string, although we anticipate 'text', and to a lesser extent 'image' and 'video' being common. | |
entityId | string | no | The entityId of the entity which owns the data the hook should be rendered using. i.e. the entity which has the hook data stored in its properties in the separately provided 'path' |
path | string | yes | A path expressed as a JSON path to a property present in the entity's schema, where the value used in rendering this view should be retrieved from and persisted to (if updated) |
hookId | string | null | yes | The ID of the hook as provided in the response when first sending a hook message. This should be null in the first 'hook' message for a given node, and use the value provided by the embedding application in 'hookResponse' on subsequent messages. |
errorCodes
: nonerespondedToBy
: hookResponsesentOnInitialization
: false
hookResponse
source
: embedderdata
: object
property | type | required | description |
---|---|---|---|
hookId | string | yes | The id of the hook, which the block can use in subsequent 'hook' messages to request that a given hook is updated. |
errorCodes
: INVALID_INPUT
, NOT_FOUND
, NOT_IMPLEMENTED
respondedToBy
: hookResponsesentOnInitialization
: false
Previous
Next
Anyone with an existing application who wants to embed semantically-rich, reusable blocks in their product can use the protocol. Improve your app’s utility and tap into a world of structured data with no extra effort, for free.
Any developer can build and publish blocks to the Hub for others to use. Contribute to an open-source community building a more interoperable future web.