Hook Service

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:

  • embedding applications providing a consistent 'look and feel' across blocks for displaying or editing values of a particular type (e.g. rich text or image editing)
  • allowing blocks to be portable across applications which use bespoke systems or data structures for displaying or editing values of a particular type (e.g. there is no universal “rich text” representation for blocks to parse and produce)

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.

Glossary

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.

Establishing hooks

Summary

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.

Specification

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:

  • it MUST:
    • render a view informed by the contents of the hook message:
      • of the appropriate type
      • by manipulating the specified node or by attaching elements within it
      • using data stored at the specified path on the entity associated with the specified entityId
    • send a hookResponse message specifying a hookId to identify the hook with in future
  • It MUST NOT destroy the node or move it within the DOM.

If 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.

Updating hooks

Summary

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.

Specification

Removing hooks

Once a hook has been established, blocks MAY request their removal by sending a hook message with the following values:

  • for hookId: the id that was provided by the embedding application in the original hookResponse message
  • for node: null
  • for entityId, type and path: whatever values are currently applied to the hook

If 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:

  • a new type to request that the type of view is changed
  • a new path to request that the data used to populate the view is retrieved from and persisted to the path on the specified entity
  • a new entityId to request that data from a new entity is used
  • a new node to request that the view is rendered at a different place in the DOM

When 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).

Hook data

Summary

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).

Specification

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.

Hook types

Summary

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.

Specification

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).

Messages

Summary

There are only two messages in the hook service: the hook request from the block, and the hookResponse acknowledgement from the embedding application.

Specification

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
A request from a block for an embedding application to render a view of the specified type, at the specified node, using the data for the specified property path.
  • source: block
  • data: object
    propertytyperequireddescription
    nodeobject | nullyesThe DOM node the embedding application will render a view into, or modifying an already rendered view. If null, the view should be destroyed.
    typeyesThe type of view for the hook. Technically permits any string, although we anticipate 'text', and to a lesser extent 'image' and 'video' being common.
    entityIdstringnoThe 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'
    pathstringyesA 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)
    hookIdstring | nullyesThe 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: none
  • respondedToBy: hookResponse
  • sentOnInitialization: false
hookResponse
A message acknowledging that the embedding application will render a view in the hook.
  • source: embedder
  • data: object
    propertytyperequireddescription
    hookIdstringyesThe 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: hookResponse
  • sentOnInitialization: false

Add blocks to your app

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.

Learn more

Build your own blocks

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.

Read the quickstart guide
We're hiring full-stack TypeScript/React developers to build blocks full-time, and grow theBlock Protocol ecosystem.Learn more