Content HAL API Add-on
Introduction
The Content HAL API Add-on enables you to provide JSON Hypertext Application Language based REST APIs from your delivery applications.
JSON Hypertext Application Language is a specification draft for HATEOAS (Hypermedia as the Engine of Application State), a constraint of the REST application architecture. Responses of HAL services are in the application/hal+json media type, and the HAL specification mostly uses Plain Old JSON as its primary design goals are generality and simplicity.
Swagger API Document Support
The Content HAL API Add-on supports Swagger API Document URL by default. For example, if you installed the Content HAL API on /api mount (e.g, http://localhost:8080/site/api), then the Swagger API Document URL will be available automatically at /api/api-docs/swagger.json (e.g, http://localhost:8080/site/api/api-docs/swagger.json) by default. So, if you installed a Swagger UI web application, then you can navigate the Content HAL API by explorering the Swagger Document URL (e.g, http://localhost:8080/site/api/api-docs/swagger.json).
Every Response Body is a HAL Resource
In a HAL API like the Content HAL API Add-on, every response must be a HAL resource.
Minimal HAL Resource Example
A minimal HAL resource can be an empty JSON object:
{ }
Typical HAL Resource Example
However, an empty HAL resource wouldn't be very useful, so it is very common to have links including "self" at least in a reserved property, "_links", like the following example:
{ "_links": { "self": { "href" : "/orders/523" } } }
So, it represents a resource with the link to itself at least.
But, in practical use cases, a resource should have more fields like the following example:
{ "_links": { "self": { "href": "/orders/523" }, "invoice": { "href": "/invoices/873" } }, "currency": "USD", "status": "shipped", "total": 10.20 }
A HAL resource can have properties with any names (currency, status, total, etc.) with links (in a reserved property, "_links") as long as it is a valid JSON object.
HAL Resource Example Embedding Other Resource(s)
A HAL resource can embed other resources, and the embedded resource may include all the fields or parts of its fields:
{ "_links": { "self": { "href": "/orders" } }, "_embedded": { "orders": [{ "_links": { "self": { "href": "/orders/523" } }, "total": 30.00 },{ "_links": { "self": { "href": "/orders/524" } }, "total": 20.00 }] } "currentlyProcessing": 14, "shippedToday": 20 }
So, suppose you get the above response from http://localhost:8080/sales/orders. The resource in this response may include all the order collection data inside the reserved property, "_embedded", as well as other fields, like shown above.
How Hippo Document is mapped to HAL Resource
Now, the question is how a Hippo document is mapped to a HAL resource. That's where the Content HAL API is expected to contribute.
The Content HAL API Add-on takes a straightforward approach. It takes the field names which were already defined through document type (a.k.a "namespace") designs. Let's see the following document type example ("Event" document type).
The "Event" document type contains multiple fields including "title", "introduction", "content", "startdate", "enddate", "location", etc. In "Path" configuration, it is defining the logical field names ("title", "introduction", "content", "startdate", "enddate", "location", etc.) which are different from the captions such as "Title", "Introduction", "Content", etc.
By the way, if you look at those in CMS Console, you will realize that those "Path" configurations are actually stored in hipposysedit:nodetype/hipposysedit:nodetype configuration in a document type (a.k.a "namespace") definition.
As the captions are only for displaying purpose, it makes sense to take the logical field names configured in "Path" configurations and use those for JSON properties in HAL resource representations like the following example:
So, an "Event" document can be represented as a JSON HAL resource by converting all the fields of the document into JSON properties by adopting the same logical field names (as configured in "Path") like the example shown above. Also, it can have links under the reserved "_links" property in the resource object to represent its own link ("self") that can be generated by HST-2 API.
Now, how about a compound field like "content" field which contains RichText data? The same rule applies to that, too!
A "Event" document has the "content" field which is type of "hippostd:html". It means that we can convert the "hippostd:html" node to another JSON object by converting each property of "hippostd:html" node type. An example is shown below:
Since "hippostd:html" node type contains a "content" property, the "content" field is expanded to a new JSON object containing "content" property that is expanded to a string JSON property.
By the way, it is just a coincidence to have two "content" fields in the example; one is defined in "Event" document, and the other is defined in "hippostd:html" compound node type itself. If you named the field in "Event" document to something else like "body", the first one would have been "body" instead.
Now, how about linked images/assets or documents in a document? For example, an "Event" document can have "image" field that has a link data to other CMS image asset node. How can we represent those links in a document in a HAL resource?
Since the "image" field contains only link information only ("hippo:docbase") which is very CMS-specific, it makes sense to include those metadata in a HAL resource, in a special property, "_meta".
All the CMS-specific metadata are included in a reserved property, "_meta", like the example shown above. The "_meta" property may contains JCR primary type name ("type"), and it may contain the link information in "mirror" (including both node UUID and node path for developer's convenience) JSON object if there's any link data. By the way, unlike "_links", "_meta" is introduced by Content HAL API Add-on as a HAL extension.
Content HAL API URL Patterns
Content HAL API Add-on provides various built-in APIs to retrieve collection of data, an item of data or resource bundles. Those APIs are probably sufficient to most use cases.
APIs to Retrieve Collection of Documents
You can retrieve a collection of documents through /documents REST API endpoint like the following example:
- http://localhost:8080/site/api/documents
So, the example request shown above will retrieve all the documents in CMS, regardless of document types.
If you want to retrieve a collection of a specific document type only instead, then you can replace /douments in URL by the specific document type name like the following example:
- http://localhost:8080/site/api/newsdocument
- http://localhost:8080/site/api/eventsdocument
- http://localhost:8080/site/api/myhippoproject:newsdocument
- http://localhost:8080/site/api/myhippoproject:eventsdocument
- ...
The first example will retrieve all the news documents only whereas the second one will retrieve all the events documents only. You can use the physical document type name such as myhippoproject:newsdocument in the URL instead of the logical name, "newsdocument" as shown in the last two examples, too. e.g, http://localhost:8080/site/api/myhippoproject:newsdocument. In general, unless you have same logical document type name in different namespaces, it might be more intuitive to use the logical names (e.g, "newsdocument") instead of physical names (e.g, "myhippoproject:newsdocument").
This kind of document collection retrieval APIs support the following query parameters in common.
[Common Query Parameters]
Name |
Required? |
Description |
Examples |
_scope |
No |
Search scope node ID or path. |
_scope=a_UUID or |
_offset |
No |
Offset of the iterating query result. |
_offset=10 |
_limit |
No |
Limit of the iterating query result. |
_limit=10 |
_fields |
No |
Comma-separated field names to include or exclude. |
_fields=title,introduction,-content |
_sort |
No |
Comma-separated sort field names. |
_sort=title,-date |
_q |
No |
Full text search query term which is used in jcr:contains(.,q) constraint in the query. |
_q=lorem+ipsum |
_expr |
No |
Custom JCR XPath expression to narrow the search result. |
_expr=jcr:contains(@my:title,'hippo') |
APIs to Retrieve Single Document
You can retrieve single document by UUID or relative path under the mount's content base path. For example,
- http://localhost:8080/site/api/documents/{UUID}
- http://localhost:8080/site/api/documents/{relPath}
- http://localhost:8080/site/api/newsdocument/{UUID}
- http://localhost:8080/site/api/newsdocument/{relPath}
- http://localhost:8080/site/api/eventsdocument/{UUID}
- http://localhost:8080/site/api/eventsdocument/{relPath}
- http://localhost:8080/site/api/myhippoproject:newsdocument/{UUID}
- http://localhost:8080/site/api/myhippoproject:newsdocument/{relPath}
- http://localhost:8080/site/api/myhippoproject:eventsdocument/{UUID}
- http://localhost:8080/site/api/myhippoproject:eventsdocument/{relPath}
- ...
For example, suppose you have a news article document at /content/documents/myhippoproject/news/2017/02/the-medusa-news and its UUID is c580ac64-3874-4717-a6d9-e5ad72080abe, then you can retrieve the content by any of the following URL examples:
- http://localhost:8080/site/api/documents/c580ac64-3874-4717-a6d9-e5ad72080abe
- http://localhost:8080/site/api/documents/news/2017/02/the-medusa-news
- http://localhost:8080/site/api/newsdocument/c580ac64-3874-4717-a6d9-e5ad72080abe
- http://localhost:8080/site/api/newsdocument/news/2017/02/the-medusa-news
- http://localhost:8080/site/api/myhippoproject:newsdocument/c580ac64-3874-4717-a6d9-e5ad72080abe
- http://localhost:8080/site/api/myhippoproject:newsdocument/news/2017/02/the-medusa-news
This kind of single document retrieval APIs support the following query parameters in common.
[Common Query Parameters]
Name |
Required? |
Description |
Examples |
_fields |
No |
Comma-separated field names to include or exclude. |
_fields=title,introduction,-content |
APIs to Retrieve Resource Bundles
Resource Bundle documents are special documents which are identified by Bundle ID (a.k.a, "basename"). So, Content HAL API Add-on supports dedicated APIs for Resource Bundle documents.
You can retrieve a collection of all the available Resource Bundles through /resourcebundles REST API endpoint like the following example:
- http://localhost:8080/site/api/resourcebundles
This API supports the following query parameters:
Name |
Required? |
Description |
Examples |
_offset |
No |
Offset of the iterating query result. |
_offset=10 |
_limit |
No |
Limit of the iterating query result. |
_limit=10 |
_q |
No |
Full text search query term which is used in jcr:contains(.,q) constraint in the query. |
_q=lorem+ipsum |
_expr |
No |
Custom JCR XPath expression to narrow the search result. |
_expr=jcr:contains(@my:title,'hippo') |
You can also retrieve single Resource Bundle data like the following example:
- http://localhost:8080/site/api/resourcebundles/{basename}
So, for example, you want to retrieve the Resource Bundle, the basename of which is essentials.global, by invoking the following URL:
- http://localhost:8080/site/api/resourcebundles/essentials.global
This API supports the following query parameters:
Name |
Required? |
Description |
Examples |
locale |
No |
Locale string. e.g, "en", "fr", "en_US", etc. |
locale=en |
APIs to Retrieve Folders
Content HAL API Add-on also supports retrievals on content folders. To retrieve a collection of folders, invoke /folders REST API endpoint:
- http://localhost:8080/site/api/folders
This API supports the following query parameters:
Name |
Required? |
Description |
Examples |
_offset |
No |
Offset of the iterating query result. |
_offset=10 |
_limit |
No |
Limit of the iterating query result. |
_limit=10 |
_sort | No | Comma-separated sort field names. No sorting by default. Note: If a field name is prefixed by "-", the specific field will be sorted in descending order. If a field name is included but not prefixed by "-", the field will be sorted in ascending order. |
|
_q |
No |
Full text search query term which is used in jcr:contains(.,q) constraint in the query. |
_q=lorem+ipsum |
_expr |
No |
Custom JCR XPath expression to narrow the search result. |
_expr=jcr:contains(@my:title,'hippo') |
You can also retrieve a specific folder content by specifying either UUID or relative folder path:
- http://localhost:8080/site/api/folders/{UUID}
- http://localhost:8080/site/api/folders/{relPath}
How to Include Site Link?
By default, a HAL resource includes a "self" link for a document (e.g, a document at content/documents/myproject/events/2019/01/introduction-speech) like the following example:
{ "_links": { "self": { "href": "http://localhost:8080/site/api/documents/18e36c35-429d-4fee-b76e-eeabcbfc08bb" } } }
Suppose you want to include "site" link as well like the following:
{ "_links": { "self": { "href": "http://localhost:8080/site/api/documents/18e36c35-429d-4fee-b76e-eeabcbfc08bb" }, "site": { "href": "http://localhost:8080/site/events/2019/01/introduction-speech.html" } } }
In this case, you should configure HST-2 mount alias mapping properly.
Here are the configuration steps you should follow:
- Set hst:alias property of the parent mount (e.g, /hst:root) of Content HAL API mount (e.g, /hst:root/api) to "site". That is, /hst:root/@hst:alias="site".
- Add hst:mountsite property (String) with a value, "site", to the Content HAL API mount (e.g, /hst:root/api). That is, /hst:root/api/@mountsite="site"
- Then Content HAL API can find the parent mount through the mapping (@hst:mountsite="site"), in its mount configuration, to the specific mount having @hst:alias="site" (i.e. /hst:root), and generate the "site" link to include it in _links property.