{"id":66119,"date":"2024-09-19T10:19:07","date_gmt":"2024-09-19T04:49:07","guid":{"rendered":"https:\/\/www.tothenew.com\/blog\/?p=66119"},"modified":"2024-09-19T13:44:01","modified_gmt":"2024-09-19T08:14:01","slug":"enabling-headless-for-existing-aem-site-part-2-2","status":"publish","type":"post","link":"https:\/\/www.tothenew.com\/blog\/enabling-headless-for-existing-aem-site-part-2-2\/","title":{"rendered":"Enabling Headless For Existing AEM Site Part 2"},"content":{"rendered":"<p>In our<a href=\"https:\/\/www.tothenew.com\/blog\/enabling-headless-for-existing-aem-site\/\"> first blog<\/a> of headless series, we discussed different approaches to enable headless for AEM existing sites. We emphasized on one approach to use sling exporters and traditional templates. Let&#8217;s discuss changes required to get this approach working.<\/p>\n<h3>Key points of the approach<\/h3>\n<ol>\n<li style=\"list-style-type: none;\">\n<ol>\n<li>Any application\/service can make HTTP calls to <a href=\"https:\/\/www.tothenew.com\/cx\/aem-development-consulting\">AEM<\/a> pages using \u201c.<strong>model.json\u201d<\/strong> selector and extension, and the whole page will be exposed as JSON. We cannot change the selector that is &#8220;model&#8221; as this selector has already been used by OOTB page components and WCM components for SPA AEM support.<\/li>\n<li>Changes are to be made in sling models for each component to make sure each component exposes its JSON as required.<\/li>\n<li>Dispatcher Changes are to be made to allow calls to pages with &#8220;<strong>.model.json<\/strong>&#8220;.<\/li>\n<li>Changes are to be made in a way which will have minimal impact on existing AEM sites.<\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<h4>Read More: <a href=\"https:\/\/www.tothenew.com\/blog\/customizing-content-fragments-with-adobe-aem-app-builder\/\">Customizing Content Fragments with Adobe AEM App Builder<\/a><\/h4>\n<h3>Changes Required to enable headless for existing site<\/h3>\n<p>We have in-house demo project called \u2018TTN Retail\u2019 from which we are going to see examples\/screenshots in the following points:<\/p>\n<ol>\n<li style=\"list-style-type: none;\">\n<ol>\n<li>\n<h4>Sling model for each component<\/h4>\n<ol>\n<li>When we call a page with &#8220;.model.json&#8221;, it iterates all components on the page and embed the component JSON exposed by their sling model and returns a single JSON. JSON looks like this:\n<p><div id=\"attachment_66116\" style=\"width: 910px\" class=\"wp-caption aligncenter\"><img aria-describedby=\"caption-attachment-66116\" decoding=\"async\" loading=\"lazy\" class=\"wp-image-66116\" src=\"https:\/\/www.tothenew.com\/blog\/wp-ttn-blog\/uploads\/2024\/09\/Screenshot-from-2024-09-09-17-44-27-1024x682.png\" alt=\"Headless JSON\" width=\"900\" height=\"599\" srcset=\"\/blog\/wp-ttn-blog\/uploads\/2024\/09\/Screenshot-from-2024-09-09-17-44-27-1024x682.png 1024w, \/blog\/wp-ttn-blog\/uploads\/2024\/09\/Screenshot-from-2024-09-09-17-44-27-300x200.png 300w, \/blog\/wp-ttn-blog\/uploads\/2024\/09\/Screenshot-from-2024-09-09-17-44-27-768x511.png 768w, \/blog\/wp-ttn-blog\/uploads\/2024\/09\/Screenshot-from-2024-09-09-17-44-27-624x415.png 624w, \/blog\/wp-ttn-blog\/uploads\/2024\/09\/Screenshot-from-2024-09-09-17-44-27.png 1421w\" sizes=\"(max-width: 900px) 100vw, 900px\" \/><p id=\"caption-attachment-66116\" class=\"wp-caption-text\">Headless JSON Example<\/p><\/div><\/li>\n<li>Sling model must use resourceType attribute in @model annotation like\n<pre>@Model(adaptables = {Resource.class, SlingHttpServletRequest.class} ,\r\n\u00a0 \u00a0 \u00a0 \u00a0 adapters = {FlatSalesListModel.class , ComponentExporter.class},\r\n\u00a0 \u00a0 \u00a0 \u00a0 resourceType = \"ttnretail\/components\/commerce\/flatsaleslist\",\r\n\u00a0 \u00a0 \u00a0 \u00a0 defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)<\/pre>\n<\/li>\n<li>Single sling model must be used to render logic on each component. Using multiple sling models on component&#8217;s HTL means information on component rendering is coming from different sources and that will not support the Sling exporter.<\/li>\n<li>Sometimes there are use cases where we want to use more than one sling model in component&#8217;s HTL as some utility. In such scenarios, it&#8217;s better to extend the other sling models in the component\u2019s primary sling model.<\/li>\n<\/ol>\n<\/li>\n<li>\n<h4>Exporter annotation<\/h4>\n<ol>\n<li>@Exporter annotation must be used on sling models.<\/li>\n<li>Use &#8216;model&#8217; as selector and &#8216;json&#8217; as extension.<\/li>\n<li>Use Jackson exporter for serialization which provides a variety of annotations for different use cases.<\/li>\n<li>Example:\n<pre>@Exporter(name=\"jackson\", selector = \"model\", extensions = \"json\")<\/pre>\n<\/li>\n<\/ol>\n<\/li>\n<li>\n<h4>Extending Component Exporter<\/h4>\n<p>Since we are using AEM&#8217;s SPAs way of getting page JSON, we need to make sure:<\/p>\n<ol>\n<li>We use &#8216;model&#8217; as selector in exporter annotation.<\/li>\n<li>Component model must extend com.adobe.cq.export.json.ComponentExporter.<\/li>\n<li>Model annotation must use ComponentExporter interface in Adapters properties like:\n<pre>@Model(adaptables = {Resource.class, SlingHttpServletRequest.class} ,\r\n\u00a0 \u00a0 \u00a0 \u00a0 adapters = {FlatSalesListModel.class , ComponentExporter.class},\r\n\u00a0 \u00a0 \u00a0 \u00a0 resourceType = \"ttnretail\/components\/commerce\/flatsaleslist\",\r\n  \u00a0 \u00a0 \u00a0 defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)<\/pre>\n<\/li>\n<li>The Component model interface must directly or indirectly extend ComponentExporter Interface.\n<pre>public interface Navigation extends ComponentExporter {}<\/pre>\n<p>Note: If your model is extending WCM Component class (com.adobe.cq.wcm.core.components.models.Component), then it already extends ComponentExporter indirectly (Refer https:\/\/github.com\/adobe\/aem-core-wcm-components\/blob\/main\/bundles\/core\/src\/main\/java\/com\/adobe\/cq\/wcm\/core\/components\/models\/Component.java).<\/li>\n<li>Component must override ComponentExporter.getExportedType() method where it must return the resourceType of the component.\n<pre>@Override\r\n\r\npublic String getExportedType() {\r\nreturn \"ttnretail\/components\/commerce\/flatsaleslist\";\r\n}<\/pre>\n<\/li>\n<\/ol>\n<\/li>\n<li>\n<h4>Dispatcher Change<\/h4>\n<p>In order to expose the page as JSON, we need to allow model selector and json extension in the filter section of dispatcher configuration. Example as given below:<\/p>\n<pre>\/filter\r\n\r\n.....\r\n\r\n# Allow JSON Extension with model selector request\r\n\r\n\/0063 { \/type \"allow\" \/path \"\/content\/ttn-retail\/*\" \/method \"GET\" \/selectors \"model\" \/extension \"json\" }<\/pre>\n<p>The path used here is the site path under which the pages exist for the site.<\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<h3>Conclusion<\/h3>\n<p>The above changes will help you achieve headless with minimal impact on existing AEM site. Stay tuned for more insightful and valuable discussions on <a href=\"https:\/\/www.tothenew.com\/cx\/aem-development-consulting\">Adobe Experience Manager<\/a>. We will further discuss on customizing the model .json of components and pages in upcoming blogs in the Headless Series.<\/p>\n<p>Are you looking to formulate effective strategies to maximize customer experience using <a href=\"https:\/\/www.tothenew.com\/cx\/adobe-experience-cloud\">Adobe Experience Cloud<\/a>? \u00a0<a href=\"https:\/\/www.tothenew.com\/contact-us\">Click here<\/a> to schedule a meeting with us.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In our first blog of headless series, we discussed different approaches to enable headless for AEM existing sites. We emphasized on one approach to use sling exporters and traditional templates. Let&#8217;s discuss changes required to get this approach working. Key points of the approach Any application\/service can make HTTP calls to AEM pages using \u201c.model.json\u201d [&hellip;]<\/p>\n","protected":false},"author":994,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":123},"categories":[5868],"tags":[4847,5008,5009],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/66119"}],"collection":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/users\/994"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/comments?post=66119"}],"version-history":[{"count":17,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/66119\/revisions"}],"predecessor-version":[{"id":66658,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/66119\/revisions\/66658"}],"wp:attachment":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/media?parent=66119"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/categories?post=66119"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/tags?post=66119"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}