{"id":60883,"date":"2024-03-21T11:50:30","date_gmt":"2024-03-21T06:20:30","guid":{"rendered":"https:\/\/www.tothenew.com\/blog\/?p=60883"},"modified":"2024-06-10T15:32:24","modified_gmt":"2024-06-10T10:02:24","slug":"enhancing-json-response-dynamically-in-aem-with-sling-filters","status":"publish","type":"post","link":"https:\/\/www.tothenew.com\/blog\/enhancing-json-response-dynamically-in-aem-with-sling-filters\/","title":{"rendered":"Enhancing JSON Response Dynamically in AEM with Sling Filters"},"content":{"rendered":"<p><span style=\"font-weight: 400;\">In the realm of web development, customizing JSON responses dynamically based on specific criteria is a common requirement. Recently, our team encountered such a scenario in Adobe Experience Manager (AEM) where we needed to modify the JSON response based on a URL value within the response itself. In this blog post, I&#8217;ll walk you through our solution using Sling Filters in AEM, along with code snippets to illustrate the implementation.<\/span><\/p>\n<h2><strong>Understanding the Requirement<\/strong><\/h2>\n<p><span style=\"font-weight: 400;\">Our requirement was to augment the main JSON response with additional data fetched from a URL provided within the response. Essentially, we needed to append the response from this URL to the main JSON structure before sending it back to the client.<\/span><\/p>\n<h2><strong>Solution Overview<\/strong><\/h2>\n<p><span style=\"font-weight: 400;\">To achieve this dynamic modification of the JSON response, we leveraged Sling Filters in AEM. Sling Filters allow us to intercept requests and responses in AEM, making them a perfect fit for our use case. Here&#8217;s an overview of the solution:<\/span><\/p>\n<ol>\n<li><b> Identify the URL within the JSON response:<\/b><span style=\"font-weight: 400;\"> We first needed to parse the incoming JSON response to locate the URL that contains the additional data we want to append.<\/span><\/li>\n<li><b> Implement a Sling Filter:<\/b><span style=\"font-weight: 400;\"> We created a custom Sling Filter that intercepts the request and response. Within this filter, we extracted the URL from the JSON response and made an HTTP request to fetch the additional data.<\/span><\/li>\n<li><b> Append data to the main JSON response: <\/b><span style=\"font-weight: 400;\">Once we retrieved the additional data from the URL, we appended it to the main JSON response.<\/span><\/li>\n<li><b> Return the modified JSON response: <\/b><span style=\"font-weight: 400;\">Finally, we returned the modified JSON response to the client.<\/span><\/li>\n<\/ol>\n<h2><strong>Implementation Steps<\/strong><\/h2>\n<p><span style=\"font-weight: 400;\">Let&#8217;s dive into the implementation details with code snippets:<\/span><\/p>\n<ol>\n<li><b> Create the Sling Filter<\/b><\/li>\n<\/ol>\n<pre><span style=\"font-weight: 400;\">@Component<\/span><span style=\"font-weight: 400;\">(service = Filter.class, immediate = <\/span><span style=\"font-weight: 400;\">true<\/span><span style=\"font-weight: 400;\">, name = <\/span><span style=\"font-weight: 400;\">\"TTN Custom JSON Filter\"<\/span><span style=\"font-weight: 400;\">, property = {<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">EngineConstants.SLING_FILTER_SCOPE + <\/span><span style=\"font-weight: 400;\">\"=\"<\/span><span style=\"font-weight: 400;\"> + \u00a0 \u00a0 <\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\"> \u00a0 \u00a0 \u00a0 EngineConstants.FILTER_SCOPE_REQUEST,<\/span><span style=\"font-weight: 400;\">\r\n<\/span> <span style=\"font-weight: 400;\">EngineConstants.SLING_FILTER_METHODS + <\/span><span style=\"font-weight: 400;\">\"=\"<\/span><span style=\"font-weight: 400;\"> + METHOD_GET,<\/span><span style=\"font-weight: 400;\">\r\n<\/span> <span style=\"font-weight: 400;\">EngineConstants.SLING_FILTER_PATTERN + <\/span><span style=\"font-weight: 400;\">\"=\"<\/span><span style=\"font-weight: 400;\"> + <\/span><span style=\"font-weight: 400;\">\"\/content\/ttn\/api\/v1\/offers\"<\/span><span style=\"font-weight: 400;\">,<\/span><span style=\"font-weight: 400;\">\r\n<\/span> <span style=\"font-weight: 400;\">EngineConstants.SLING_FILTER_SELECTORS + <\/span><span style=\"font-weight: 400;\">\"=\"<\/span><span style=\"font-weight: 400;\"> + model,<\/span><span style=\"font-weight: 400;\">\r\n<\/span> <span style=\"font-weight: 400;\">EngineConstants.SLING_FILTER_EXTENSIONS + <\/span><span style=\"font-weight: 400;\">\"=\"<\/span><span style=\"font-weight: 400;\"> + <\/span><span style=\"font-weight: 400;\">\"json\"<\/span><span style=\"font-weight: 400;\"> })<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">public<\/span> <span style=\"font-weight: 400;\">class<\/span> <span style=\"font-weight: 400;\">CustomJsonFilter<\/span> <span style=\"font-weight: 400;\">implements<\/span> <span style=\"font-weight: 400;\">Filter<\/span><span style=\"font-weight: 400;\"> {<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">\u00a0 \u00a0 <\/span><span style=\"font-weight: 400;\">@Reference<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">\u00a0 \u00a0 <\/span><span style=\"font-weight: 400;\">private<\/span><span style=\"font-weight: 400;\"> HttpClient httpClient;<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">\u00a0 \u00a0 <\/span><span style=\"font-weight: 400;\">@Override<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">\u00a0 \u00a0 <\/span><span style=\"font-weight: 400;\">public<\/span> <span style=\"font-weight: 400;\">void<\/span> <span style=\"font-weight: 400;\">doFilter<\/span><span style=\"font-weight: 400;\">(ServletRequest request, ServletResponse response, FilterChain chain) <\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"font-weight: 400;\">throws<\/span><span style=\"font-weight: 400;\"> IOException, ServletException {<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">try<\/span><span style=\"font-weight: 400;\"> {<\/span><span style=\"font-weight: 400;\">\r\n<\/span> <span style=\"font-weight: 400;\">apiUrlResponseMap = <\/span><span style=\"font-weight: 400;\">new<\/span><span style=\"font-weight: 400;\"> HashMap&lt;&gt;();<\/span><span style=\"font-weight: 400;\">\r\n<\/span> <span style=\"font-weight: 400;\">SlingHttpServletRequest slingRequest = (SlingHttpServletRequest) request;<\/span><span style=\"font-weight: 400;\">\r\n<\/span> <span style=\"font-weight: 400;\">SlingHttpServletResponse modelResponse = <\/span><span style=\"font-weight: 400;\">new<\/span><span style=\"font-weight: 400;\"> \u00a0 offerSlingModelResponseWrapper((SlingHttpServletResponse) response);<\/span><span style=\"font-weight: 400;\">\r\n<\/span> <span style=\"font-weight: 400;\">chain.doFilter(slingRequest, modelResponse);<\/span><span style=\"font-weight: 400;\">\r\n<\/span> <span style=\"font-weight: 400;\">PrintWriter responseWriter = response.getWriter();<\/span><span style=\"font-weight: 400;\">\r\n<\/span> <span style=\"font-weight: 400;\">updateJson(modelResponse.toString(), responseWriter);<\/span><span style=\"font-weight: 400;\">\r\n<\/span> <span style=\"font-weight: 400;\">} <\/span><span style=\"font-weight: 400;\">catch<\/span><span style=\"font-weight: 400;\"> (ServletException | IOException e) {<\/span><span style=\"font-weight: 400;\">\r\n<\/span> <span style=\"font-weight: 400;\">logger.error(<\/span><span style=\"font-weight: 400;\">\"doFilter: Exception Occurred: {}\"<\/span><span style=\"font-weight: 400;\">, e.getMessage());<\/span><span style=\"font-weight: 400;\">\r\n<\/span> <span style=\"font-weight: 400;\">}<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">\u00a0 \u00a0 }<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">\/**<\/span><span style=\"font-weight: 400;\">\r\n<\/span> <span style=\"font-weight: 400;\"> * Iterates the json response of cms api<\/span><span style=\"font-weight: 400;\">\r\n<\/span> <span style=\"font-weight: 400;\"> * <\/span><span style=\"font-weight: 400;\">\r\n<\/span> <span style=\"font-weight: 400;\"> * @param modelResponse\u00a0 the response object<\/span><span style=\"font-weight: 400;\">\r\n<\/span> <span style=\"font-weight: 400;\"> * @param responseWriter the printWriter object<\/span><span style=\"font-weight: 400;\">\r\n<\/span> <span style=\"font-weight: 400;\"> *\/<\/span><span style=\"font-weight: 400;\">\r\n<\/span> <span style=\"font-weight: 400;\">protected<\/span> <span style=\"font-weight: 400;\">void<\/span> <span style=\"font-weight: 400;\">updateJson<\/span><span style=\"font-weight: 400;\">(String modelResponse, PrintWriter responseWriter) {<\/span><span style=\"font-weight: 400;\">\r\n<\/span> <span style=\"font-weight: 400;\">\/\/ write down the logic to update the json response<\/span><span style=\"font-weight: 400;\">\r\n<\/span> <span style=\"font-weight: 400;\">}<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">\u00a0 \u00a0 <\/span><span style=\"font-weight: 400;\">@Override<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">\u00a0 \u00a0 <\/span><span style=\"font-weight: 400;\">public<\/span> <span style=\"font-weight: 400;\">void<\/span> <span style=\"font-weight: 400;\">init<\/span><span style=\"font-weight: 400;\">(FilterConfig filterConfig) <\/span><span style=\"font-weight: 400;\">throws<\/span><span style=\"font-weight: 400;\"> ServletException {<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"font-weight: 400;\">\/\/ Do nothing<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">\u00a0 \u00a0 }<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">\u00a0 \u00a0 <\/span><span style=\"font-weight: 400;\">@Override<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">\u00a0 \u00a0 <\/span><span style=\"font-weight: 400;\">public<\/span> <span style=\"font-weight: 400;\">void<\/span> <span style=\"font-weight: 400;\">destroy<\/span><span style=\"font-weight: 400;\">() {<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"font-weight: 400;\">\/\/ Cleanup logic<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">\u00a0 \u00a0 }<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">}<\/span><\/pre>\n<ol start=\"2\">\n<li><b> Implement HTTP Client Service<\/b><\/li>\n<\/ol>\n<pre><span style=\"font-weight: 400;\">\/**<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\"> * Http Request Data Service component that returns the API response in String<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\"> *<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\"> *\/<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">@Component<\/span><span style=\"font-weight: 400;\">(service = HttpRequestDataService.class, immediate = <\/span><span style=\"font-weight: 400;\">true<\/span><span style=\"font-weight: 400;\">)<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">public<\/span> <span style=\"font-weight: 400;\">class<\/span> <span style=\"font-weight: 400;\">HttpRequestDataServiceImpl<\/span> <span style=\"font-weight: 400;\">implements<\/span> <span style=\"font-weight: 400;\">HttpRequestDataService<\/span><span style=\"font-weight: 400;\"> {<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">\u00a0 \u00a0 <\/span><span style=\"font-weight: 400;\">@Override<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">\u00a0 \u00a0 <\/span><span style=\"font-weight: 400;\">public<\/span><span style=\"font-weight: 400;\"> String <\/span><span style=\"font-weight: 400;\">invokeHttpRequest<\/span><span style=\"font-weight: 400;\">(URL endpointUrl) {<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"font-weight: 400;\">\/\/ Make HTTP request to fetch additional data<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"font-weight: 400;\">\/\/ Return response body as String<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">\u00a0 \u00a0 }<\/span><span style=\"font-weight: 400;\">\r\n<\/span><span style=\"font-weight: 400;\">}<\/span><\/pre>\n<h2><strong>Conclusion<\/strong><\/h2>\n<p><span style=\"font-weight: 400;\">By utilizing Sling Filters in AEM, we successfully achieved dynamic modification of JSON responses based on specific criteria. This approach not only met our requirement but also demonstrated the flexibility and extensibility of AEM in handling diverse use cases.<\/span><\/p>\n<div class=\"ap-custom-wrapper\"><\/div><!--ap-custom-wrapper-->","protected":false},"excerpt":{"rendered":"<p>In the realm of web development, customizing JSON responses dynamically based on specific criteria is a common requirement. Recently, our team encountered such a scenario in Adobe Experience Manager (AEM) where we needed to modify the JSON response based on a URL value within the response itself. In this blog post, I&#8217;ll walk you through [&hellip;]<\/p>\n","protected":false},"author":1745,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":213},"categories":[5868,4488],"tags":[4847,5008,1521,5720],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/60883"}],"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\/1745"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/comments?post=60883"}],"version-history":[{"count":3,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/60883\/revisions"}],"predecessor-version":[{"id":60894,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/60883\/revisions\/60894"}],"wp:attachment":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/media?parent=60883"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/categories?post=60883"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/tags?post=60883"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}