Loading...
Area: Optimizely Content Delivery API
Applies to versions: 2.9 and higher
Other versions:

How to customize data returned to clients

Recommended reading 

There are two approaches to customize how response data is returned for requests.

  1. Use Select parameter in endpoints
  2. Use IContentFilter and IContentApiModelFilter

Select parameter in endpoints

All endpoints in Content Delivery API lets you filter data returned to requests by using the parameter "select".

The property names expected in the response should be assigned to the parameter and separated by comma. The value of this parameter is extracted and passed to ConverterContext.SelectedProperties for later use. The image below shows an example with a Get endpoint, but the result format should be the same for other ones as well. For endpoints related to GetChildren and GetAncestor, data filtering is applied for each item returned to clients.  As can be seen, property names are not case sensitive and properties contentLink, name, and language are always returned regardless of parameter value.

imagequ6uh.png

One limitation for this feature is that it cannot be applied for expanded values. In the case where clients send a request and expect properties to be expanded, the expanded value still show full data without filtering it according to select param. This is illustrated in the image below. Although some properties are passed in param, the expanded value pageImage still shows full data as normal. 

image0sst.png

Use IContentFilter and IContentApiModelFilter

Although IContentFIlter and IContentApiModelFilter has been marked as Preview for safety purposes for a long time, they have been stable and are worth being used for customization purpose. The preview may be removed in a coming .NET Core version of Content Delivery API.

The diagram below illustrates how IContent is converted into ContentAPIModel, which is then serialized and returned to clients. The select parameter in the request mentioned in section Select parameter in endpoints is extracted and passed to ConverterContext. It is then used by ContentApiModelMinifier in the diagram to filter data. 

This section focuses on two other ways to filter data with IContentFilter and IContentApiModelFilter. 

imageqb5gh3.png

IContentFilter

The IContent Filtering phase takes responsibility to filter IContent data before it is converted to ContentApiModel.Within this phase, the IContent properties can be filtered according to specific rules. The code sample below shows an example of how to filter data using IContentFilter. The filter impacts on ExpandedValue as well. 

[ServiceConfiguration(typeof(IContentFilter), Lifecycle = ServiceInstanceScope.Singleton)] 

    internal class CustomContentFilter : ContentFilter<IContent> 
    { 
        public override void Filter(IContent content, ConverterContext converterContext) 
        { 
            content.Property.Remove("PageImage"); 
            content.Property.Remove("MainContentArea"); 
        } 
    } 

The code sample is simple, but other services or HttpContext can be used to do more filtering within the class (for example, pass some parameters in the request and extract them by using HttpContext or injected services for more data manipulation).

With the given code above, the properties PageImage and MainContentArea are removed from IContent, meaning that they will not appear in the conversion phase later on. As a result, they will disappear in the result returned to clients. The downside of IContentFilter is that it is still not possible to remove some default properties of ContentApiModel like ExistingLanguages, MasterLanguage, etc. 

Note: Some properties are mandatory (for example, PageLink and PageTypeID, if content is a page) and those should not be removed in the filter. Otherwise, exceptions are thrown in the conversion phase later on. 

IContentApiModelFilter

After IContent is converted to ContentApiModel, and before data is returned to clients (or minified based on select parameter), the ContentApiModel data can be filtered in the ContentApiModel Filtering phase. This can be done  like in the code sample below. The sample use select parameter mentioned above. 

  [ServiceConfiguration(typeof(IContentApiModelFilter), Lifecycle = ServiceInstanceScope.Singleton)]
    internal class CustomContentApiModelFilter : ContentApiModelFilter<ContentApiModel>
    {
        public override void Filter(ContentApiModel contentApiModel, ConverterContext converterContext)
        {
            // Select param mentioned in the first part of article is retrieved and passed to ConverterContext.SelectedProperties
            // but it's only for the parent content. In case that clients contain childs that can be expanded, the param value is not served for them.
            // so that we need to extract param like the following if we want to apply select param for child elements.
            
            var selectedParamValue= string.Empty;
            if (HttpContext.Current.Request.QueryString["select"] == null)
            {
                return;
                
            }
            selectedParamValue = HttpContext.Current.Request.QueryString["select"].ToString();
            var selectedProperties = string.IsNullOrWhiteSpace(selectedParamValue) ? new HashSet<string>() : new HashSet<string>(selectedParamValue.Split(',').Select(x => x.Trim()), StringComparer.OrdinalIgnoreCase);

            try
            {
                var dictProp = new Dictionary<string, object>();
                contentApiModel.Properties = contentApiModel.Properties.Where(entry => selectedProperties.Contains(entry.Key))
                                                                       .ToDictionary(entry => entry.Key, entry => entry.Value);

                // Set those values below as null, and configure ContentApiOption.IncludeNullValues = false in Initialization
                // then, response data will not include those ones. 
                contentApiModel.ExistingLanguages = null;
                contentApiModel.MasterLanguage = null;
                contentApiModel.ParentLink = null;
                contentApiModel.Language = null;
                contentApiModel.StartPublish = null;
                contentApiModel.StopPublish = null;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }

As in the example above, IContentApiModelFilter lets you remove default ContentApiModel properties and filter data returned by using select parameter. The filter is activated each time an IContent is converted to ContentApiModel . This means it has effect on nested elements or items in ContentArea in an expanded scenario as well, which makes the response body much cleaner and lighter. ContentApiOption.IncludeNullValue should be set to false in the configuration for this sample.

A final note for this article is that in case where the whole conversion phase should be customized for a specific reason, ContentConvertingService (a public service) can be used to fulfill the requirement. However, this is not highly recommended due to the complexity to handle IContent.

Do you find this information helpful? Please log in to provide feedback.

Last updated: Jun 24, 2021

Recommended reading