Customize the Content HAL API Add-on - BloomReach Experience - Open Source CMS
19-04-2019

Customize the Content HAL API Add-on

BloomReach offers Enterprise support for this feature to BloomReach Experience customers. The release cycle of this feature may differ from our core product release cycle. 

How to Extend the Services?

The built-in Content HAL APIs will be sufficient in most practical use cases. However, Content HAL API provides some extension points for customizability.

Spring Assembly Overrides

Content HAL API Add-on services are assembled in Spring Beans assembly XML files in classpath*:META-INF/hst-assembly/addon/com/onehippo/cms7/addon/halapi/*.xml resources.

If you want to customize any built-in service beans and if you're knowledgeable enough to do that, then you may want to override the bean definitions defined in classpath*:META-INF/hst-assembly/overrides/addon/com/onehippo/cms7/addon/halapi/*.xml resources.

What if I want to change the default parameters (such as page size)?

The default page size is 10, which can be overriden at runtime by the _limit query parameter as explained in the Content HAL Addon page. But in some cases, you might want to increase or decrease the default value even if the caller doesn't pass the _limit query parameter. Content HAL API Add-on allows to set any default query parameters by overridding the halRestApiServiceQueryStringReplacingInterceptor bean in an overriding assembly XML (e.g, classpath*:META-INF/hst-assembly/addon/com/onehippo/cms7/addon/halapi/custom-hal-params.xml):

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean id="halRestApiServiceQueryStringReplacingInterceptor"
        class="org.hippoecm.hst.jaxrs.cxf.QueryStringReplacingInterceptor">
    <property name="paramNameReplaces">
      <map>
        <!--
        The following will replace '_format' parameter name with '_type'
        <entry key="_format" value="_type" />
        -->
      </map>
    </property>
    <property name="additionalQueryString">
      <value></value>
      <!--
      The following will set _limit parameter to 100 by default.
      <value>_limit=100</value>
      -->
      <!--
      Or the following will append additional query string before JAX-RS processing
      <value>addparam1=value1&amp;addparam2=value2</value>
      -->
    </property>
  </bean>

</beans>

The halRestApiServiceQueryStringReplacingInterceptor bean provides a generic way to replace or append query parameters:

  • If you add entries to paramNameReplaces property, you can replace parameter names at runtime. For example, if you want to allow callers to use "pageSize" as well as "_limit" query parameter, you can add <entry key="pageSize" value="_limit" />, and then callers can use "pageSize" or "_limit" to specify the page size.
  • If you set an extra query string in additionalQueryString property, the extra query string is always set in every invocation by default. For example, if you set the property to "_limit=100", the page size is set to 100 by default unless the caller passes _limit parameter explicitly. If the caller makes a request with an explicit _limit query parameter, the explicit query parameter takes the precedence because the additionalQueryString property is simply appended to the invocation URI at the end.

What if I want to decorate the returned HAL Resource JSON objects?

You can implement a custom JcrContentHalResourceProcessor in order to add any extra properties, metadata or embedded resources by yourself:

public MyCustomHalResourceProcessor implements JcrContentHalResourceProcessor {

    @Override
    public boolean isProcessable(Node contentNode) {
        // Suppose we want to add one more extra property called 'externalSource' only for myproject:externallysourced document variant node type.
        return contentNode.isNodeType("myproject:externallysourced");
    }

    @Override
    public ContentHalResource process(ContentHalResource resource, Node contentNode) {
        // Suppose we want to add one more extra property called 'externalSource' like the following.
        // In advanced cases, you might want to enrich the resource by adding additional properties from external data sources, too.
        resource.setProperty("externalSource", JcrUtils.getStringProperty(contentNode, "myproject:externalsource", "");
    }
}
#isProcessable(...) method shown in the above example has become available since v2.0.2. In the previous versions, you had to add that kind of conditions in #process(...) method.

To register your custom JcrContentHalResourceProcessor, add a custom addon Spring assembly XML under classpath:META-INF/hst-assembly/overrides/addon/com/onehippo/cms7/addon/halapi/ to define your custom JcrContentHalResourceProcessor list bean (The bean ID must be "customContentHalResourceProcessors").

For example, add site/components/src/main/resources/META-INF/hst-assembly/overrides/addon/com/onehippo/cms7/addon/halapi/custom-hal-processors.xml like the following:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd">

  <bean id="customContentHalResourceProcessors"
        class="org.springframework.beans.factory.config.ListFactoryBean">
    <property name="sourceList">
      <list>
        <bean class="com.example.hal.MyCustomHalResourceProcessor">
        </bean>
      </list>
    </property>
  </bean>
</beans>

What if I want to add a new plain JAX-RS service?

Add a Spring Bean assembly XML file under classpath:META-INF/hst-assembly/overrides/addon/com/onehippo/cms7/addon/halapi/. e.g. site/components/src/main/resources/META-INF/hst-assembly/overrides/addon/com/onehippo/cms7/addon/halapi/custom-extra-plain-jaxrs.xml.
And add your custom plain JAX-RS service beans (e.g. com.example.hal.jaxrs.service.MyExtraCustomJaxrsResource)  into customHalRestApiResourceProviders ListFactoryBean like the following example. Note that the list bean ID must be customHalRestApiResourceProviders.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd">

  <!-- Default empty list of custom plain resource providers to be overriden. -->
  <bean id="customHalRestApiResourceProviders"
    class="org.springframework.beans.factory.config.ListFactoryBean">
    <property name="sourceList">
      <list>
        <bean class="org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider">
          <constructor-arg>
            <bean class="com.example.hal.jaxrs.service.MyExtraCustomJaxrsResource">
            </bean>
          </constructor-arg>
        </bean>
      </list>
    </property>
  </bean>
</beans>

If the custom plain JAX-RS service bean is annotated with a different path in the class level, it will work for that specific path with your custom service bean. For example, you sometimes might want to add a custom plain JAX-RS service bean to create or update document by POST invocation.

Did you find this page helpful?
How could this documentation serve you better?
On this page
    Did you find this page helpful?
    How could this documentation serve you better?