This topic describes how to customize the Optimizely Content Delivery API to change data returned to clients.
Note: This documentation only applies to version 2.6.1 and lower of the API. We are currently working on updating it for the latest version.
ContentResultService
This service takes responsibility to handle data before returning it to clients. Here, this class is customized so that it can limit the payload returned to clients. With this customized class, only fields needed by clients can be returned through the API.
- Create a new class, CustomContentResultService, and decorate it with ServiceConfiguration(typeof(ContentResultService)).
- Register this new class as the default instance for ContentResultService in InitializationModule.
-
Endpoint sample should be http://localhost:8080/api/episerver/v2.0/content/12?fields=contentLink,name,language,productPageLinks,relatedContentArea,mainContentArea.
Code example from Alloy template site:
[ServiceConfiguration(typeof(ContentResultService))]
public class CustomContentResultService : ContentResultService
{
public CustomContentResultService(IContentApiSerializer contentApiSerializer) : base(contentApiSerializer)
{
}
public override StringContent BuildContent(object value)
{
var fields = System.Web.HttpContext.Current.Request.Params["fields"];
if (string.IsNullOrEmpty(fields) || !(value is ContentApiModel))
{
return base.BuildContent(value);
}
var returnedProperties = fields.Split(',');
var convertedObj = new ExpandoObject() as IDictionary<string, Object>;
Func<string[], string, bool> shouldIncludeProperty = (propertyList, property) =>
{
return propertyList.Any(prop => string.Equals(prop, property, StringComparison.InvariantCultureIgnoreCase));
};
foreach (var prop in value.GetType().GetProperties())
{
var propertyType = prop.PropertyType;
if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(IDictionary<,>))
{
var propertyDataDict = prop.GetValue(value, null);
foreach (var item in propertyDataDict as IDictionary<string, object>)
{
if (!shouldIncludeProperty(returnedProperties, item.Key))
{
continue;
}
convertedObj.Add(item.Key, item.Value);
}
continue;
}
if (!shouldIncludeProperty(returnedProperties, prop.Name))
{
continue;
}
var propValues = prop.GetValue(value, null);
convertedObj.Add(prop.Name, propValues);
}
return base.BuildContent(convertedObj);
}
}
[InitializableModule]
public class DependencyResolverInitialization : IConfigurableModule
{
public void ConfigureContainer(ServiceConfigurationContext context)
{
context.ConfigurationComplete += (o, e) =>
{
context.Services.AddTransient<IContentRenderer, ErrorHandlingContentRenderer>()
.AddTransient<ContentAreaRenderer, AlloyContentAreaRenderer>()
.AddTransient<ContentResultService, CustomContentResultService>();
};
}
public void Initialize(InitializationEngine context)
{
DependencyResolver.SetResolver(new ServiceLocatorDependencyResolver(context.Locate.Advanced));
}
public void Uninitialize(InitializationEngine context)
{
}
public void Preload(string[] parameters)
{
}
}
ContentAreaPropertyModel
By default, the Content Delivery API only expands content at one level in depth. In this section, ContentAreaPropertyModel is customized so that it can expand all property levels in ContentArea.
- Create a new class, CustomContentAreaPropertyModel, which inherits from ContentAreaPropertyModel and overrides the ExtractExpandedValue() method. Basically, this calls _contentModelMapper.TransformContent with the expand parameter Is set to "*". (The default value is empty which is why only one property level is expanded to reduce the response payload.)
- Create a new class, CustomContentAreaPropertyConverter, which inherits from DefaultPropertyModelConverter and register the newly created CustomContentAreaPropertyModel.
public class CustomContentAreaPropertyModel : ContentAreaPropertyModel
{
public CustomContentAreaPropertyModel(PropertyContentArea propertyContentArea,bool excludePersonalizedContent)
: base(propertyContentArea, excludePersonalizedContent)
{
}
protected override IEnumerable<ContentApiModel> ExtractExpandedValue(CultureInfo language)
{
var expandedValue = new List<ContentApiModel>();
var contentReferences = Value.Where(x => x.ContentLink != null).Select(x => new ContentReference(x.ContentLink.Id.Value));
var content = _contentLoaderService.GetItems(contentReferences, language).ToList();
var principal = ExcludePersonalizedContent ? _principalAccessor.GetAnonymousPrincipal() : _principalAccessor.GetCurrentPrincipal();
var filteredContent = content.Where(x => _accessEvaluator.HasAccess(x, principal, AccessLevel.Read)).ToList();
filteredContent.ForEach(x => expandedValue.Add(_contentModelMapper.TransformContent(x, ExcludePersonalizedContent, "*")));
return expandedValue;
}
}
[ServiceConfiguration(typeof(IPropertyModelConverter), Lifecycle = ServiceInstanceScope.Singleton)]
public class CustomContentAreaPropertyConverter : DefaultPropertyModelConverter
{
public override int SortOrder { get; } = 100;
protected override IEnumerable<TypeModel> InitializeModelTypes()
{
var typeList = new List<TypeModel>();
typeList.Add(new TypeModel()
{
PropertyType = typeof(PropertyContentArea),
ModelType = typeof(CustomContentAreaPropertyModel),
ModelTypeString = typeof(CustomContentAreaPropertyModel).FullName
});
return typeList;
}
}
Related topics
Last updated: Jun 24, 2021