Customizing Layout Service For Including Custom Fields In Layout Service Response

While working with Sitecore JSS, I observed that be default Layout Service API doesn't fetch all the basic Sitecore fields in the response. We have to manually configured which fields we want for a particular component in the response of Layout Service.


For example, for a particular component, only ID, URL, Name & Display Name fields are returned by the layout service in it's response. Suppose we also want to get TemplateID & TemplateName of a particular component in the response, along with the mentioned field, then it is not included in the response of Layout Service Out Of The Box. For that we have to customize the layout service response.


Now it can get a bit complex, as we will have to first peek into the default implementation of Layout Service response & then customize based on our needs. For that we need to decompile Sitecore.LayoutService assembly using any decompiler (For Eg. JetBrains' dotPeek) specifically ContentsResolvers class to understand default implementation.


This will involve creating a Custom Resolver class from by including the fields in ResolveContents function which we want in the response :


public class CustomDatasourceResolver : Sitecore.LayoutService.ItemRendering.ContentsResolvers.IRenderingContentsResolver
    {
        public bool IncludeServerUrlInMediaUrls { get; set; } = true;

        public bool UseContextItem { get; set; }

        public string ItemSelectorQuery { get; set; }

        public NameValueCollection Parameters { get; set; } = new NameValueCollection(0);

        public object ResolveContents(Rendering rendering, IRenderingConfiguration renderingConfig)
        {
            //if you want to access the datasource item
            var datasource = !string.IsNullOrEmpty(rendering.DataSource)
                ? rendering.RenderingItem?.Database.GetItem(rendering.DataSource)
                : null;

            var datasourceTemplateId = datasource.TemplateID.ToString();
            var datasourceTemplateName = datasource.TemplateName.ToString();

            return new
            {
                templateId = datasourceTemplateId,
                templateName = datasourceTemplateName
            };

        }


        protected virtual IEnumerable<Item> GetItems(Item contextItem)
        {
            Assert.ArgumentNotNull((object)contextItem, nameof(contextItem));
            return string.IsNullOrWhiteSpace(this.ItemSelectorQuery) ? Enumerable.Empty<Item>() : (IEnumerable<Item>)contextItem.Axes.SelectItems(this.ItemSelectorQuery);
        }

        protected virtual Item GetContextItem(
          Sitecore.Mvc.Presentation.Rendering rendering,
          IRenderingConfiguration renderingConfig)
        {
            if (this.UseContextItem)
                return Context.Item;
            if (string.IsNullOrWhiteSpace(rendering.DataSource))
                return (Item)null;
            Item obj = rendering.RenderingItem?.Database.GetItem(rendering.DataSource);
            if (obj != null)
                return obj;
            DataUri uri = DataUri.Parse(rendering.DataSource);
            if (!(uri != (DataUri)null))
                return (Item)null;
            return rendering.RenderingItem?.Database.GetItem(uri);
        }

        protected virtual JArray ProcessItems(
          IEnumerable<Item> items,
          Sitecore.Mvc.Presentation.Rendering rendering,
          IRenderingConfiguration renderingConfig)
        {
            JArray jarray = new JArray();
            foreach (Item obj in items)
            {
                JObject jobject1 = this.ProcessItem(obj, rendering, renderingConfig);
                JObject jobject2 = new JObject()
                {
                    ["id"] = (JToken)obj.ID.Guid.ToString(),
                    ["url"] = (JToken)LinkManager.GetItemUrl(obj, ItemUrlHelper.GetLayoutServiceUrlOptions()),
                    ["name"] = (JToken)obj.Name,
                    ["displayName"] = (JToken)obj.DisplayName,
                    ["fields"] = (JToken)jobject1
                };
                jarray.Add((JToken)jobject2);
            }
            return jarray;
        }

        protected virtual JObject ProcessItem(
          Item item,
          Sitecore.Mvc.Presentation.Rendering rendering,
          IRenderingConfiguration renderingConfig)
        {
            Assert.ArgumentNotNull((object)item, nameof(item));
            using (new SettingsSwitcher("Media.AlwaysIncludeServerUrl", this.IncludeServerUrlInMediaUrls.ToString()))
                return JObject.Parse(renderingConfig.ItemSerializer.Serialize(item));
        }
    }

Next we need to create a config file which will patch this class to the Sitecore Layout Service pipeline :


 <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
    <sitecore>
        <layoutService>
            <configurations>
                <config name="jss-rendering">
                    <rendering>
                        <renderingContentsResolver type="[Class Name with Namespace], [Assembly Name]"
                                                   patch:after="*[@type='Sitecore.LayoutService.ItemRendering.ContentsResolvers.RenderingContentsResolver, Sitecore.LayoutService']">
                            <IncludeServerUrlInMediaUrls>false</IncludeServerUrlInMediaUrls>
                        </renderingContentsResolver>
                    </rendering>
                </config>
            </configurations>
        </layoutService>
    </sitecore>
</configuration>

Next, we need to create a custom Rendering Content Resolver which will include our custom class.


Navigate to /sitecore/system/Modules/Layout Service/Rendering Contents Resolvers in Content Tree. Right click on Rendering Contents Resolvers folder & create a new Custom Rendering Contents Resolver :

In Type Field, Enter name of your Custom Contents Resolver class with namespace followed by assembly name in the format : Namespace.ClassName, AssemblyName :



Next, use this contents resolver configuration item for the JSON rendering in the Rendering Contents Resolver field of Layout Service section for which you want those additional sitecore fields in the response (TemplateID, TemplateName) :


Publish all of your changes. That's it now you should see your fields (TemplateID, TemplateName) in the layout service response.


107 views0 comments

Recent Posts

See All

With NextJS SDK, in order to render Image, first we need to import the ImageField & Image interfaces from sitecore-jss npm package : import { Image, ImageField} from '@sitecore-jss/sitecore-jss-nextjs