The solution design journey for headless CMS implementation using Adobe Experience Manager
In this article I am going to talk about my recent experience with headless CMS implementation using AEM.
What was the challenge?
The challenge was to keep the UI with third party applications built using custom solutions (eg. .Net application, SPA built on Angular Framework etc) but let the content come from CMS. This would allow the business to edit some of the information being displayed on website without IT release.
First baby step:
We were lucky to have a smaller project on our way to test some of the capabilities in a very limited scope. In this project there was only one AEM component and we were required to send all the pages data created using that component in json format. But that helped us the set the paradigm.
Since there were not many variations, we started with a simple json structure agreed upon by both CMS and consuming application.
The next bigger piece:
When the smaller project was successful with the limited scope, people started to accept the fact that it is doable :) and more such request to implement AEM as headless CMS whilst keeping UI with existing system started to float.
As the project scope increased, so as the need to make the solution more scalable. With the first project we were only looking at same json each time, but with the latest one there was need to get content in variations.
For eg.
1. Get me content of a single product (For product detail page) vs get me content of all products (For category page)
2. Get me content for a user who has not purchased a subscription vs for a user who has already has purchased.
The challenge here was to support more components and not just the one like earlier use case. Also, a demand to support dynamic components and not binding the API to always look for same (eg. product detail) component always. This also required the need of JSON structure which is better maintained both for AEM and consuming app.
To support multiple components (not the pre-baked but those which author can decide), we provided a parsys and allowed the authors to add component to it. API would then check the resource type of the component in the parsys one by one and will decide what type of json to generate based on the component. Still the logic to generate json was in java class that managed the business rules, making it bound to that API.
Create loose coupling between Component JSON and API:
This was the cornerstone for catering json which is not bound to specific component.
Building Blocks:
· Model
The component should be self-sufficient to generate JSON irrespective of whether it is being used in single vs aggregated result. We used SlingModels for this. Each component has associated SlingModel class which has a method to return required json. Another advantage of this pattern is that it will always generate same json no matter from which API it is being called. This streamlines the process. If there is a change in json structure, you don’t have to go and change 4 different classes specific for each API. Model class is always single source of truth.
· Helper
We introduced a helper class which has got the business logic behind how to package the json received from individual component. Servlet only listens for the request coming for given resource type and selector. Then it forwards the request to specific helper which internally knows what all information should be passed with the json (eg. adding metadata for some templates, aggregating the json results etc.)
The helper class had if else if ladder to go over fixed set of components. Let’s consider the scenario. If there are 5 components (A,B,C,D and E) in the system and A,B and C are allowed in template T1. The if else if ladder only looks for A,B and C components while generating json. Now, if there is a need to allow D and E as well on Template T1, we would need to add extra else if statements for D and E. This needs an IT release.
· Model Utility
Above limitation led to the birth of a Model Utility class. This class had if else if ladder for all allowed components in the system and not specific for any template. Now, if a component already being used in Template T2, needs to be used in T1 as well, it does not need an IT release J - This was the biggest win from CMS perspective. Definitely, there would be need of IT release from UI perspective to render the new component data at desired place on page.
The advantages of above pattern:
1. Servlet only looks for incoming resource type (template), selector, and extension combination and directs request to Helper class. Then it does not have to bother until Helper class does its job and bring back json. The json would then be returned by servlet back to consuming application.
2. Business logic is in separate class making it flexible to change without touching the API generation
3. Model Utility to check which model to invoke based on the resource type is in separate class. This makes it re-usable across several APIs as same set of components are in use across system but with different templates.
4. Models with json generation are self-sufficient without bound to any API. This makes it easily modifiable without touching business logic in API. Same json structure would be generated irrespective of what APIs are calling this.
What is missing?
The limitation right now is that each time a new component is introduced in CMS, a new condition needs to be added in the ladder under Model Utility to check its resource type and call appropriate model. If there is a way to map the component on page with its model, that would make this pattern the most beautiful :)
Hello Ronak, Good Article. One doubt, Was there a situation where you had to shara images/any other dam assets with consuming assets. How did you handle the access