Customizing the Layout Service rendering output

Abstract

Using GraphQL queries or Rendering Contents Resolver to tweak the Layout Service output

When serializing a rendering to JSON, the Layout Service populates the rendering contents with the fields of the rendering's datasource item.

Occasionally, you might want the output to include some other types of data, such as:

  • Data from the context item.

  • Data from datasource or context item children.

  • Data from other items altogether.

  • A more limited view of any of the previously mentioned types of data to avoid over-fetching unneeded data.

  • A computed or otherwise more complex value.

  • Non-item data, such as information from xDB.

  • Non-Sitecore data from external systems.

The following sections describe some of the options for customizing the rendering output returned by the Layout Service.

Using the GraphQL API

You can customize he Layout Service output for a Sitecore rendering can be customized by configuring a GraphQL query on the rendering. In JSS, this technique is referred to as integrated GraphQL. The query runs server-side during the Layout Service request, or at publish time if using Experience Edge.

When the Sitecore Layout Service renders a page, it returns a JSON representation of the layout of the page and the data for each rendering/component. Normally the rendering/component data is a set of fields from the Sitecore datasource item. Integrated GraphQL lets you re-shape this into a GraphQL query result.

To use this technique, you must:

  • Define a Sitecore GraphQL endpoint that has the schema you want to query.

  • Configure your application to use the endpoint. For example:

    <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
      <sitecore>
        <javaScriptServices>
          <apps>
            <!-- you may override other attributes from 'defaults' in the app definition below -->
            <app name="JssBasicAppGraphQL"
                 graphQLEndpoint="/sitecore/api/jssbasicappgraphql"
                 inherits="defaults"
            />
          </apps>
        </javaScriptServices>
      </sitecore>
    </configuration>

Integrated GraphQL operates by storing the GraphQL query in the Component GraphQL Query field on the component's rendering item. For example, the GraphQL sample app sets a query on /sitecore/layout/Renderings/JssBasicAppGraphQL/IntegratedPage.

The Component GraphQL Query field on a rendering

When Sitecore receives a layout request, if a component defines a GraphQL query that is not empty, the query is run against the GraphQL endpoint configured for the app, in-process. The result replaces the normal rendering field values that are returned.

Choosing or configuring a built-in Rendering Contents Resolver

Headless Services lets you configure a Rendering Contents Resolver on each rendering, to determine how a rendering and its associated data are serialized. Rendering Contents Resolvers are configured in /sitecore/system/Modules/Layout Service/Rendering Contents Resolvers. By default, Headless Services provides the following resolvers:

  • Datasource Resolver - the default behavior. It serializes the rendering's datasource item.

  • Datasource Item Children Resolver - serializes the children of the datasource item.

  • Context Item Resolver - serializes the context item instead of the datasource item.

  • Context Item Children Resolver - serializes the children of the context item.

  • Folder Filter Resolver - serializes the descendants of the datasource item, excluding folders.

You can create your own configuration in the Rendering Contents Resolvers folder using the following available parameters:

  • Type - this is Sitecore.LayoutService.ItemRendering.ContentsResolvers.RenderingContentsResolver, Sitecore.LayoutService, unless you are creating your own implementation.

  • Include Server URL in Media URLs - always check this field unless you run a front-end app built with JSS in Integrated mode.

  • Use Context Item - use the context item instead of the datasource item.

  • Item Selector Query - provide a Sitecore query to customize the serialized items. This must be relative to the datasource and/or context item, depending on the selection above.

    Important

    When using this parameter, be aware that it is easy to create Sitecore queries with a severe negative performance impact.

  • Parameters - provide arbitrary parameters. These are not used by default but are potentially useful when creating your own implementation.

Creating an IRenderingContentsResolver interface

The Layout Service lets you fully customize the contents of a serialized rendering with the help of the IRenderingContentsResolver interface.

Important

Whenever possible, for future compatibility, we recommend you use one of the previous no-code options.

You can override the default IRenderingContentsResolver interface on a rendering by creating your own implementation and creating a Rendering Contents Resolver item, specifying your custom Type. For example:

public class ExampleRenderingContentsResolver : Sitecore.LayoutService.ItemRendering.ContentsResolvers.IRenderingContentsResolver
{
    public bool IncludeServerUrlInMediaUrls { get; set; }
    public bool UseContextItem { get; set; }
    public string ItemSelectorQuery { get; set; }
    public NameValueCollection Parameters { get; set; }

    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;

        return new
        {
            name = datasource.Name,
            date = DateTime.Now,
            hello = "world"
        };
    }
}

The fields of the object returned by your implementation can then be bound to your front-end components as if they were item content (for example, props in React).

Tip

You can extend the Sitecore.LayoutService.ItemRendering.ContentsResolvers.RenderingContentsResolver class and use the ProcessItem method from the class to enable rendering item fields for advanced Sitecore editors.

Why not a separate REST endpoint?

For some of the scenarios above, you could create a separate REST endpoint to access the needed data. However, the techniques above offer several advantages:

  • Avoid additional HTTP roundtrip(s).

  • Automatically bind the data to the component.

  • Make the data available for server/universal rendering.

  • Make it easier to query additional data related to the current application, context item (route), or datasource item.

Why not extend the Layout Service context data?

There is some overlap between potential uses, but extending the context data returned by the Layout Service is generally intended for information that might be used in multiple components, or for providing data for statically placed components not managed within a Placeholder. These approaches also ensure the data is made available when, and only when a content author utilizes that rendering within a route.