Loading...
Area: Optimizely Content Management API
Applies to versions: 2 and higher

Deserialization

Recommended reading 

When receiving a request, the Content Management API first deserializes the data from the request body into models, and then, handle the request.

In this topic

How it works

The Content Management API defines some input models (ContentApiCreateModel, ContentApiPatchModel), which play a role as data transform objects for the deserialization process. Basically, data is transformed to those models before being converted to IContent and saved to the database. For example, the diagram below illustrates the scenario of creating a new content item.

Deserialization.jpg

The workflow follows the below steps:

  • You make a request to Post new content endpoint with an input model in JSON format.
  • The server accepts the request and transforms the JSON data into ContentApiCreateModel. Some metadata fields are mapped automatically, and the custom properties are converted to PropertyModel.
  • Before saving the content, the ContentApiCreateModel is migrated to the IContent. The list of PropertyModel is converted to the PropertyData, then added to the IContent.Property.

The flow is the same for all endpoints.

Customizing the deserialization

If you define a custom PropertyData in your model, you need to register a custom PropertyModel and a custom converter to determine which PropertyData corresponds to which PropertyModel. For example, you have a custom property PropertyStringList which inherits the PropertyLongString:

[EditorHint(Global.SiteUIHints.Strings)]
[PropertyDefinitionTypePlugIn(Description = "A property for list of strings", DisplayName = "String List")]
public class PropertyStringList : PropertyLongString
{
    protected String Separator = "\n";

    public String[] List
    {
        get
        {
            return (String[])Value;
        }
    }

    public override Type PropertyValueType
    {
        get
        {
            return typeof(String[]);
        }
    }

    public override object SaveData(PropertyDataCollection properties)
    {
        return LongString;
    }

    public override object Value
    {
        get
        {
            var value = base.Value as string;

            if (value == null)
            {
                return null;
            }

            return value.Split(Separator.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
        }
        set
        {
            if (value is String[])
            {
                var s = String.Join(Separator, value as String[]);
                base.Value = s;
            }
            else
            {
                base.Value = value;
            }
        }
    }
}

For Content Management API to handle this custom property, you need to register a corresponding StringListPropertyModel:

public class StringListPropertyModel : PropertyModel<IList<string>, PropertyStringList>
{
    [JsonConstructor]
    internal StringListPropertyModel() : this(new PropertyStringList()) { }

    public StringListPropertyModel(PropertyStringList propertyStringList) : base(propertyStringList)
    {
        Value = propertyStringList.List;
    }
}

And a StringListPropertyDataValueConverter that implements the IPropertyDataValueConverter:

[ServiceConfiguration(typeof(IPropertyDataValueConverter))]
[PropertyDataValueConverter(new Type[] { typeof(StringListPropertyModel) })]
internal class StringListPropertyDataValueConverter : IPropertyDataValueConverter
{
    ///<inheritdoc />
    public object Convert(IPropertyModel propertyModel, PropertyData propertyData)
    {
        if (propertyModel is null)
        {
            throw new ArgumentNullException(nameof(propertyModel));
        }

        return ((StringListPropertyModel)propertyModel).Value;
    }
}

Data format

Flatten configuration controls whether the deserialized representation of properties should only include the value of all properties rather than both value and property type (for POST/PUT/PATCH requests). This should be carefully noted because it has impact on the data format send to endpoints.

public void ConfigureContainer(ServiceConfigurationContext context)
{
    context.ConfigurationComplete += (o, e) =>
    {
        context.Services.Configure<ContentManagementApiOptions>(c =>
        {
            // enable flatten model. It is disabled by default (false)
            c.SetFlattenPropertyModel(true);
        });
    };
}

With flatten model disabled, the data format is as below:

 "money": {
    "value": 2,
    "propertyDataType": "PropertyNumber"
},
"double": {
    "value": 3.3,
    "propertyDataType": "PropertyFloatNumber"
},
"pageReference": {
    "value": {
    "id": 6,
    "workId": 0,
    "guidValue": "b386494f-f4b8-4872-adc0-e83290f1752a",
    "providerName": null,
    "url": "/en/alloy-plan/",
    "expanded": null
  },
 "propertyDataType": "PropertyPageReference"
}

With flatten model enabled, the data format is:

"money" : 222,
"double": 222.5,
"pageReference" : {
  "id": 9,
  "workId": 0,
  "guidValue": "d9272d3c-5432-4928-9f45-398c2b60ab9a",
  "providerName": null,
  "url": "/alloy-track"
}
Do you find this information helpful? Please log in to provide feedback.

Last updated: Apr 20, 2021

Recommended reading