Blogs > Content as a Service in AEM
AEM Sites
Content as a Service in AEM
| November 12, 2024Hi, hope you are doing well. Welcome to another blog.
Content as a Service in AEM
Content as a Service in AEM is a powerful feature of AEM that circulates content in structured format like JSON instead of serving it as mear webpages thus aiding in its usage across multiple platforms including mobile apps, IoT devices. This content can be consumed by various other websites, applications, and devices.
Features of Content as a Service in AEM
Content as a Service thus provides a variety of powerful features that include:
-
Headless Content Delivery : Headless content delivery in AEM is like having a supercharged content hub that feeds all your digital experiences—websites, mobile apps, kiosks, or even smart devices—without being tied to a specific front-end design.
Think of AEM as the brain of your content. It stores and manages everything—text, images, videos, structured data—and makes it available through APIs. These APIs act like messengers, delivering content to any front-end framework you choose, whether it’s React, Angular, Vue.js, or even something new in the future.
This setup gives developers the freedom to build fast, modern, and interactive applications while letting content creators work in AEM without worrying about code. It’s a flexible, scalable way to keep content consistent across platforms, ensuring that updates happen in one place but appear everywhere your audience interacts with your brand.
-
Content Fragments in AEM are like neatly organized content blocks that you can create once and reuse across multiple platforms. They help structure content in a way that’s flexible, consistent, and API-friendly, making them perfect for headless content delivery. Once created, these fragments can be referenced anywhere within AEM pages, or they can be delivered directly to websites, mobile apps, or other digital platforms through APIs. For more details on content fragments, refer our blog on content fragments.
-
GraphQL & REST APIs : If you're familiar with GraphQL, you'll love AEM’s implementation. Instead of making multiple requests to retrieve different pieces of content, GraphQL lets you ask for exactly what you need in a single request. This makes content delivery faster and more efficient, reducing unnecessary data transfers. It’s perfect for structured content like product catalogs, blogs, FAQs, and content fragments, where you only want specific fields rather than an entire data set. For more details refer our Graphql blog where the content fragments are actualy exported using GraphQL
AEM content Services also supports REST APIs, provides a flexible way to fetch content in JSON format. It follows a more traditional API structure, where each request retrieves predefined content endpoints. This is useful when you need to integrate AEM with other systems or when working with applications that rely on RESTful architecture.
Here we will be creating a few content fragments which store data of stars. This data will be then exported as a JSON RESTful API endpoint.
Creation of Content Fragment Model and respective Content Fragments.
To begin with, we need to have a few content fragments that stores the data of stars. We will be creating a content fragment model and proceed with adding content fragments.
-
Navigate to tools and then to assets and then to content fragments. Here you can see a few folders. Go to your project folder and then create a content Fragment model.
-
Having created the content fragment model, we need to create a few content fragments. To do so, navigate to navigations, assets and then files. Now create a folder, here we have created Stars Data folder.
-
Within this folder will reside all the content fragments. To do so, we need to add the folder where in there exists our content fragment model in the cloud configurations of the stars data folder. Select the folder and go to properties and in cloud configurations, add the path of the folder in which we have the content fragment model.
-
Having done so, we have created a few content fragmengs which are now ready to be exported.
Endpoint Creation
Now we have all the prerequisits ready for the creation of an endpoint which will sore the data of the content fragments. Here is the code snippet for the same which we will be understanding.
package com.local.core.constants;
public class StarEndpointConstant {
public static final String ENDPOINTPATH = "/bin/stars";
public static final String STAR_PARENT_FOLDER_PATH = "/content/dam/stars-data";
public static final String STAR_MASTER = "/jcr:content/data/master";
public static final String STAR_NAME = "starName";
public static final String DATEOFDISCOVERY = "discoveryDate";
public static final String SPECTRALINFO = "spectralType";
public static final String SPECTRUM = "spectrum";
public static final String SOLAR_MASS = "solarMass";
public static final String IS_PART_OF_BINARY_STAR_SYSTEM = "isPartOfBinaryStarSystem";
public static final String PART_OF_BINARY_STAR_SYSTEM = "Part of Binary Star System";
public static final String DISCOVERY = "discovery";
}
package com.local.core.servlets;
import com.local.core.constants.StarEndpointConstant;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.json.JSONException;
import org.json.JSONObject;
import org.osgi.service.component.annotations.Component;
import javax.jcr.*;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
@Component(service = {Servlet.class}, property = {
"sling.servlet.paths="+ StarEndpointConstant.ENDPOINTPATH,
"sling.servlet.methods=GET"
})
public class StarsServlet extends SlingSafeMethodsServlet {
private String discoveryDate;
private List spectral;
private String solarMass;
private String isPartOfBinaryStarSystem;
@Override
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
ResourceResolver resolver = request.getResourceResolver();
Resource resource= resolver.getResource(StarEndpointConstant.STAR_PARENT_FOLDER_PATH);
Node starData = resource.adaptTo(Node.class);
try {
JSONObject starJSONObject = new JSONObject();
NodeIterator stars = starData.getNodes();
while(stars.hasNext()){
Node star = stars.nextNode();
String name = star.getName();
if(!name.contains(":")){
Node starMaster = resolver.getResource(star.getPath()+ StarEndpointConstant.STAR_MASTER).adaptTo(Node.class);
String starName = starMaster.getProperty(StarEndpointConstant.STAR_NAME).getValue().getString();
JSONObject starDataJsonObject = new JSONObject();
JSONObject starSpectrumJsonObject = new JSONObject();
if(starMaster.hasProperty(StarEndpointConstant.DATEOFDISCOVERY)){
Calendar calendar = starMaster.getProperty(StarEndpointConstant.DATEOFDISCOVERY).getValue().getDate();
int year = calendar.get(calendar.YEAR);
int month = calendar.get(calendar.MONTH);
int day = calendar.get(calendar.DAY_OF_MONTH);
discoveryDate = year + "-" + month + "-" + day;
starDataJsonObject.put(StarEndpointConstant.DISCOVERY, discoveryDate);
}
if(starMaster.hasProperty(StarEndpointConstant.SPECTRALINFO)){
spectral = new ArrayList<>();
Value[] spectralProperties = starMaster.getProperty(StarEndpointConstant.SPECTRALINFO).getValues();
for(Value spectralProperty : spectralProperties) {
spectral.add(spectralProperty.toString());
}
for(String spectrum : spectral){
starSpectrumJsonObject.put(spectrum.split(":")[0], spectrum.split(":")[1]);
}
starDataJsonObject.put(StarEndpointConstant.SPECTRUM,starSpectrumJsonObject);
}
if(starMaster.hasProperty(StarEndpointConstant.SOLAR_MASS)){
solarMass = starMaster.getProperty(StarEndpointConstant.SOLAR_MASS).getValue().toString();
starDataJsonObject.put(StarEndpointConstant.SOLAR_MASS, solarMass);
}
if(starMaster.hasProperty(StarEndpointConstant.IS_PART_OF_BINARY_STAR_SYSTEM)){
if(starMaster.getProperty(StarEndpointConstant.IS_PART_OF_BINARY_STAR_SYSTEM).getBoolean()){
starDataJsonObject.put(StarEndpointConstant.PART_OF_BINARY_STAR_SYSTEM, "YES");
}else{
starDataJsonObject.put(StarEndpointConstant.PART_OF_BINARY_STAR_SYSTEM, "YES");
}
}
starJSONObject.put(starName, starDataJsonObject);
}
}
out.println(starJSONObject);
} catch (RepositoryException e) {
throw new RuntimeException(e);
} catch (IllegalArgumentException illegalArgumentException) {
illegalArgumentException.printStackTrace();
} catch (JSONException jsonException){
jsonException.printStackTrace();
}
}
}
Now let us step by step understand what does this code tries to do.
-
We have created a servlet which is registered by path and we expect to recieve a json response from this servlet when this path is hit.
@Component(service = {Servlet.class}, property = { "sling.servlet.paths="+ StarEndpointConstant.ENDPOINTPATH, "sling.servlet.methods=GET" })
-
We are mapping all the properties defined in the content fragments (star name, date of discovery, spectral, is part of binary star system and solar mass).
-
starSpectrumJsonObject puts all the spectal data. This is a multi field property, and so the spectral property value is first added in a List of String and then is added in starSpectrumJsonObject with key as substring before ":" and value as after ":". Having collected this data, it is then added in starDataJsonObject.
if(starMaster.hasProperty(StarEndpointConstant.SPECTRALINFO)){ spectral = new ArrayList<>(); Value[] spectralProperties = starMaster.getProperty(StarEndpointConstant.SPECTRALINFO).getValues(); for(Value spectralProperty : spectralProperties) { spectral.add(spectralProperty.toString()); } for(String spectrum : spectral){ starSpectrumJsonObject.put(spectrum.split(":")[0], spectrum.split(":")[1]); } starDataJsonObject.put(StarEndpointConstant.SPECTRUM,starSpectrumJsonObject); }
-
Discovery date is a date object added. This date object extracted using calendar object and constants.
if(starMaster.hasProperty(StarEndpointConstant.DATEOFDISCOVERY)){ Calendar calendar = starMaster.getProperty(StarEndpointConstant.DATEOFDISCOVERY).getValue().getDate(); int year = calendar.get(calendar.YEAR); int month = calendar.get(calendar.MONTH); int day = calendar.get(calendar.DAY_OF_MONTH); discoveryDate = year + "-" + month + "-" + day; starDataJsonObject.put(StarEndpointConstant.DISCOVERY, discoveryDate); }
-
This is then added in the starJSONObject and this is provided in the response of the code.
Conclusion
We have now understood how content fragments are exported as a JSON RESTful API endpoint. This created response is now ready to be consumed by any other application.
I hope you enjoyed the learing and have found the blog informative.