Delivery API 1.0
Info: Delivery API 1.0 is available starting from brXM 14.3.0.
Info: This page documents Delivery API version 1.0.
brXM 15.x uses Delivery API version 1.0 by default.
brXM 14.x uses Delivery API version 0.9 by default. You can enable Delivery API version 1.0 through configuration.
Overview
The Delivery API (previously known as the Page Model API) provides a built-in JSON API for representing page models and their components. It is designed to:
- Offer an intuitive, built-in JSON API for model contribution and aggregation.
- Integrate with the WCMS delivery tier and channel management features.
The API exposes a generic resource representation, while supporting dynamic page models composed of component representations, content, and domain-specific models. Developers can contribute model objects to the aggregated page representation from component implementations without writing boilerplate code.
The Delivery API exposes a REST endpoint. For a channel served at http://localhost:8080/site/, the API is available at http://localhost:8080/site/resourceapi/. The JSON response includes models for components, content items, menus, and other domain-specific objects. Single Page Applications (SPAs) can consume this API to implement the delivery tier and integrate with channel management.
You can use standard HST APIs to contribute content items or domain-specific models to the page model. See Model Contribution API for more information.
Delivery API Version 1.0
After you configure the Delivery API, it becomes available to SPAs at the child mount path (such as /resourceapi), as set by the @hst:pagemodelapi property. The HST Container automatically adds a child mount for the Delivery API, named according to the @hst:pagemodelapi property. This child mount uses the PageModelPipeline, which is similar to the default website pipeline but does not invoke rendering phases (such as FreeMarker or JSP templates). Instead, it processes model collection, page model aggregation, and JSON serialization.
SPAs can consume all aggregated models for a page. For example, if the SPA loads from http://localhost:8080/site/myapp/ or http://localhost:8080/site/myapp/news/, the API endpoint is http://localhost:8080/site/myapp/resourceapi/ or http://localhost:8080/site/myapp/resourceapi/news/. You can also create links in server-side code using the standard org.hippoecm.hst.core.linking.HstLinkCreator API.
The Delivery API follows HATEOAS principles. An SPA accesses the REST application through an HST navigational URL and receives an aggregated page model. This model contains all data needed to construct the page. Example request and response:
GET /site/resourceapi/ HTTP/1.1
Host: localhost:8080
Accept: application/json
...
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://localhost:3000
API-Version: 1.0
Content-Type: application/json;charset=UTF-8
Content-Length: ...
...
{
"meta":{
"visitor":{
"id":"fc9240d1-31d7-4f0d-bbd1-5dd3e291628c",
"header":"_visitor",
"new":false
},
"visit":{
"id":"0f706603-6045-4240-8138-39c62d92a669",
"new":false
},
"version":"1.0",
"branch":"master"
},
"links":{
"self" : {
"href" : "http://localhost/site/resourceapi",
"type" : "external"
},
"site" : {
"href" : "/",
"type" : "internal"
}
},
"channel":{
"info":{
"props":{
"title" : "Test SPA"
}
}
},
"root":{
"$ref":"/page/u1f0e3c3dc4c942bfb13130def8714ccd"
},
"document" : {
"$ref" : "/page/u1ca07af9cdf54bdd9908f991245bb062"
},
"page":{
"u1f0e3c3dc4c942bfb13130def8714ccd":{
"type" : "component"
...
},
...
...
...
"u1ca07af9cdf54bdd9908f991245bb062":{
"type" : "document"
...
},
}
}
In Delivery API v1.0, the JSON response flattens objects of several key classes and their subclasses, including HstComponent, HippoDocumentBean, CommonMenu, and Pagination. You can also mark custom objects to be flattened using the PageModelEntity marker interface.
In version 0.9, the HstComponent tree was serialized as a JSON hierarchy, and only content entries (HippoDocumentBean instances) were flattened. In version 1.0, both the HstComponent tree and the SiteMenu (which extends CommonMenu) are flattened. The SiteMenu now appears as a separate entry under /page instead of being embedded in an HstComponent object.
Structure of Flattened JSON Objects
HstComponent Tree
Assume a component hierarchy with a parent and two child components. The serialization appears as follows:
"root":{ "$ref":"/page/uid1" }, "page":{ "uid1":{ "id":"r3", "links":{ ... }, "meta":{ ... }, "name":"homepage", "type":"component", "componentClass":"org.hippoecm.hst.core.component.GenericHstComponent", "children":[ { "$ref":"/page/uid2" }, { "$ref":"/page/uid3" } ] }, "uid2":{ "type":"component" ... }, "uid3":{ "type":"component" ... } }
In this example, the root component (id: "r3") has two child components.
HstComponent ParamsInfo and Parameters
An HstComponent configuration can include parameters. Some are defined via the ParametersInfo interface, others via Dynamic Component Parameters, and some are not reflected by either. Parameters defined by ParametersInfo or Dynamic Component Parameters are serialized under paramsInfo, while others appear under params. Example:
"root":{ "$ref":"/page/uid1" }, "page":{ "uid1":{ "id":"r3", "links":{ ... }, "meta":{ "paramsInfo" : { "pageSize" : "5" }, "params" : { "color" : "red" } },
HstComponent ParamsInfo for Referenced Documents
If ParamsInfo contains a reference to another document, image set, or asset (typically via a method with the @JcrPath annotation or the equivalent in Dynamic Component Parameters), the value is replaced with a JSON Pointer reference. For example:
"meta":{ "paramsInfo" : { "relPath" : "banner/summer-sale" "absPath" : "/content/documents/myproject/banners/banner/summer-sale" } }
In Delivery API v1.0, this is replaced with:
"page" : { "uid1":{ "meta":{ "paramsInfo" : { "relPath" : "/page/uid6" "absPath" : "/page/uid6" } } }, "uid6":{ "type":"imageset" ... } }
Any referenced document, image set, or asset from component properties is included in the JSON response. This is especially relevant for Experience Page Documents, which often reference other documents, banners, or products.
HstComponent Model Objects
If an HST component sets a model as a request attribute (such as a menu or document), that object is serialized as a flattened entry, and the component references it. If multiple components reference the same object, it is serialized only once. For example, given the following Java code:
public void doBeforeRender(final HstRequest request, final HstResponse response) { HstRequestContext requestContext = request.getRequestContext(); final NewsBean newsBean = getNewsBean(.....) request.setModel("menu", requestContext.getHstSiteMenus().getSiteMenu("main")); request.setModel("document", requestContext.getContentBean()); request.setModel("news", newsBean); request.setModel("news-again", newsBean); }
The resulting JSON structure is:
"root":{ "$ref":"/page/uid1" }, "document":{ "$ref":"/page/uid3" }, "page":{ "uid1":{ "id":"r3", "links":{ "self":{ "href":"https://localhost/site/resourceapi?_hn:type=component-rendering&_hn:ref=r3", "type":"external" } }, "meta":{ "definitionId":"hst:pages/homepage", "params":{ } }, "name":"homepage", "type":"component", "componentClass":"org.hippoecm.hst.core.component.GenericHstComponent", "children":[.......], "models" : { "menu" : { "$ref" : "/page/uid2" },{ "document" : { "$ref" : "/page/uid3" }, "news" : { "$ref" : "/page/uid4" }, "news-again" : { "$ref" : "/page/uid4" }, } }, "uid2":{ "type":"menu" ... } "uid3":{ "type":"document" ... }, "uid4":{ "type":"document" ... } }
Menu Serialized Format
A serialized menu has the following structure:
"u93b2dee8ffda4a61804b4cf15ec6a285":{ "type":"menu", "links":{ }, "meta":{ }, "data":{ "name":"main", "siteMenuItems":[ { "depth":0, "repositoryBased":false, "properties":{ "hst:referencesitemapitem":"root", "hst:parameternames":[ "css class" ], "hst:parametervalues":[ "home" ] }, "name":"home", "childMenuItems":[ ], "parameters":{ "css class":"home" }, "links":{ "site":{ "href":"/", "type":"internal" } } }] } } }
Menus are hierarchical and can include child menu items in childMenuItems. Flattening is applied to the entire menu, not to individual menu items.
Document Serialized Format
A serialized document typically includes a type field, links for URL information, meta for Experience Manager preview data, and a data section with document contents. If the document references other documents, image sets, or assets, those are also flattened. Example:
{ "type":"document", "links":{ "site":{ "href":"/news/2015/08/2013-harvest.html", "type":"internal" } }, "meta":{ }, "data":{ "name":"2013-harvest", "displayName":"2013 harvest", "date":1440571980000, "source":"", "title":"2013 harvest", "introduction":"Lorem ipsum dolor sit amet", "author":"Alfred Anonymous", "image":{ "$ref":"/page/ubeff458ee07a40658cad8d96b67d13ec" }, "location":"Rome", "content":{ "value":" <p>Lorem ipsum dolor sit amet</p> " }, "localeString":"en", "id":"30092f4e-2ef7-4c72-86a5-8ce895908937" } }
ImageSet Serialized Format
ImageSet objects are serialized with type imageset and include all image variants and their URLs:
"udb02dde500984488a72c2a4fc6d51beb" : { "type" : "imageset", "links" : { }, "meta" : { }, "data" : { "name" : "picture.jpeg", "displayName" : "picture.jpeg", "description" : null, "original" : { "name" : "hippogallery:original", "displayName" : "hippogallery:original", "width" : -1, "height" : -1, "lastModified" : 1236880917884, "mimeType" : "image/jpeg", "filename" : "picture_original.jpeg", "size" : 168981, "links" : { "site" : { "href" : "http://localhost/site/binaries/unittestcontent/gallery/picture.jpeg", "type" : "resource" } } }, "thumbnail" : { "name" : "hippogallery:thumbnail", "displayName" : "hippogallery:thumbnail", "width" : -1, "height" : -1, "lastModified" : 1236880917884, "mimeType" : "image/jpeg", "filename" : "picture_thumbnail.jpeg", "size" : 1490, "links" : { "site" : { "href" : "http://localhost/site/binaries/thumbnail/unittestcontent/gallery/picture.jpeg", "type" : "resource" } } }, "fileName" : null, "localeString" : null, "id" : "db02dde5-0098-4488-a72c-2a4fc6d51beb" } }
Pagination Serialized Format
HstComponent instances that extend DocumentQueryDynamicComponent use a org.hippoecm.hst.component.pagination.Pagination object to represent search results. The object includes:
- List of results for the current page
- Total number of results
- Number of items per page
- Total number of pages
- Current page number
Because Pagination implements PageModelEntity, it is flattened in the response. The items field contains $ref pointers to the included results:
"uid7": { "offset": 0, "items": [ { "$ref": "/page/u7467739e33b84a35b6b31659eb90fc67" }, { "$ref": "/page/u5b49b58f903d4a91823a1b00fbabbf66" }, { "$ref": "/page/uc28bf4536f834377a2ab219e6f71e72c" }, { "$ref": "/page/u3046c7d1d14c42e9b13aa96d3c1ba819" }, { "$ref": "/page/u9decc66350a340c3820cd6feaf06bab3" }, { "$ref": "/page/ud94d39a9badb45419bf65d23e10f0aa3" } ], "total": 58, "first": { "number": 1, "links": { "site": { "href": "?r22_r1_r4:page=1&r22_r1_r4:limit=3", "type": "internal" }, "self": { "href": "http://localhost/site/resourceapi?r22_r1_r4:page=1&r22_r1_r4:limit=3", "type": "external" } } }, "previous": null, "current": { "number": 1, "links": { "site": { "href": "?r22_r1_r4:page=1&r22_r1_r4:limit=3", "type": "internal" }, "self": { "href": "http://localhost/site/resourceapi?r22_r1_r4:page=1&r22_r1_r4:limit=3", "type": "external" } } }, "next": { "number": 2, "links": { "site": { "href": "?r22_r1_r4:page=2&r22_r1_r4:limit=3", "type": "internal" }, "self": { "href": "http://localhost/site/resourceapi?r22_r1_r4:page=2&r22_r1_r4:limit=3", "type": "external" } } }, "last": { "number": 10, "links": { "site": { "href": "?r22_r1_r4:page=10&r22_r1_r4:limit=3", "type": "internal" }, "self": { "href": "http://localhost/site/resourceapi?r22_r1_r4:page=10&r22_r1_r4:limit=3", "type": "external" } } }, "pages": [ { "number": 1, "links": { "site": { "href": "?r22_r1_r4:page=1&r22_r1_r4:limit=3", "type": "internal" }, "self": { "href": "http://localhost/site/resourceapi?r22_r1_r4:page=1&r22_r1_r4:limit=3", "type": "external" } } }, { "number": 2, "links": { "site": { "href": "?r22_r1_r4:page=2&r22_r1_r4:limit=3", "type": "internal" }, "self": { "href": "http://localhost/site/resourceapi?r22_r1_r4:page=2&r22_r1_r4:limit=3", "type": "external" } } }, { "number": 3, "links": { "site": { "href": "?r22_r1_r4:page=3&r22_r1_r4:limit=3", "type": "internal" }, "self": { "href": "http://localhost/site/resourceapi?r22_r1_r4:page=3&r22_r1_r4:limit=3", "type": "external" } } } ], "size": 6, "enabled": true }
Specific Object Fields
type
The type field indicates the object type. Known values include:
For HstComponent:
componentcontainercontainer-item
For HippoDocumentBean:
documentassetimageset
For CommonMenu:
menu
You can use the type field to filter objects in SPAs or GraphQL layers. For example, the frontend might ignore menu objects on subsequent requests.
ctype (HstComponent)
If an HstComponent has a non-null value for getCType, the ctype field is present in the serialized JSON. The ctype value helps SPAs identify the component type. In Delivery API v0.9, this information was often communicated using the hst:label. In Delivery API v1.0, with Dynamic Component Parameters, ctype serves as a contract between the SPA and backend components.
Best Practice: Retrieving Model Objects in Applications
Although every HST Content Bean model is referenced by a JSON Pointer ($ref) by default, design your SPA to handle both referenced and embedded objects. Both approaches use the same logical JSON schema.
In JavaScript, check if the model object contains a $ref field. If so, resolve the reference using a JSON Pointer library. Otherwise, use the object directly. Example:
import jsonpointer from 'jsonpointer'; //... // Assume 'pageModel' is the root JSON object and 'models' is the 'models' field of a component. let documentWrapper = models.document; let document; if (documentWrapper['$ref']) { // Resolve the reference using the JSON Pointer library. let documentRef = documentWrapper['$ref']; document = jsonpointer.get(pageModel, documentRef); } else { // Use the embedded object directly. document = documentWrapper; } // Now you can access fields on the 'document' object... // ...
See the Demo Project and its source code for more examples.
Hint: Always check whether a model is referenced by a JSON Pointer or embedded when reading data in your SPA. This approach is future-proof, as future versions may add more model objects to the top-level
contentfield for efficiency.
Maximum Content Item Reference Depth Level
When an HST Content Bean is referenced by an HstComponent, it is included as a flattened object at reference depth level 1. If that content item references another content item, the second item is at depth level 2. By default, only items at depth level 1 are included. Deeper references are represented as JSON Pointers, unless another HstComponent directly references them.
The default maximum content item reference depth is 1. If the maximum depth is reached, the reference is serialized as a JSON Pointer. The SPA can use the UUID from the pointer to fetch the content with a separate request. (Note: support for fetching by UUID is not yet implemented.)
Changing the Maximum Content Item Reference Depth
Increasing the maximum content item reference depth can negatively impact performance. Bloomreach recommends keeping the default value of 1.
You can change the maximum depth in two ways:
- Per request
- System-wide default setting
[Content truncated]