3/9/19

Omit Data Members with JavaScript and CSharp

When calling Restful APIs with a well define JSON contract, we get errors on the request when we submit a JSON payload that does not meet the contract specification.  In many cases, we use a model that may have properties which we need to ignore from the payload before submitting to the API. In this article, we take a look at how a data member can be omitted to maintain the JSON contract definition using both JavaScript on the device side and C# for our backend services.



Defining Our Contract

For the context of this article, we are working on a telemetry API with the following JSON contract which only captures the device id and telemetry information like temperature, humidity and sound levels.


Telemetry {
deviceId (integeroptional),
temperature (numberoptional),
humidity (numberoptional),
sound (numberoptional)
}

Omit a Data Member in JavaScript

From the device side, we are capturing the information with JavaScript.  There many other data points that we capture on the device, but we only want to send the properties listed on the JSON contract. There are several approaches to rebuild the model and capture the properties that we need. On this article, we will take a look at the approach of cloning the contract and mapping properties to a new object.  Let’s take a look at our solution using JavaScript.


var device = {
    "deviceId": 2026,
    "humidity": 65,
    "location": "stock-23450",
    "sn": "br52552endn",
    "sound": 120,
    "bu": "mfr2939",
    "ver": "3.4.0",
    "robot": "rb5625",
    "temperature": 35,
};

var contract = {
    "deviceId": 0,
    "temperature": 0,
    "humidity": 0,
    "sound": 0,
}


function cloneAndMap(device, contract) {

    var data = null;

    if (device) {

        var data = Object.assign({}, contract);

        for (var key in data) {

            data[key] = device[key];

        }

    }

    return data;

}

var data = cloneAndMap(device, contract);


As shown in the code, the device object has several more properties that are not relevant to our API. We want to be able to get only the properties that are defined on our contract object.  A way to do this is to clone the contract object using Object.assign native API to shallow copy the object. We then read every key from our contract object and use those keys to get the values from our device object. The main logic is handled by the cloneAndMap function.

We should note that objects in JavaScript are dynamic data types that are essentially hash tables. This enables us to have constant time ( time complexity O(1) – one operation to access the data ) access to the hash table values by using the key for each field. This works out well for us because the device data can have hundreds of fields, but we will access each field in constant time. We are only bound to the contract object size which is much smaller and well define to n=4 fields, so the time complexity to traverse all the contract keys is O(4).

We should also note that we are cloning the contract object because we want to continue to reuse it for other API calls. We also decided not to clone the device object because its running time T(n)  would depend on the size (n) of all its properties which is much larger than the contract. We would then need to delete the unwanted properties, but we know that objects in JavaScript are immutable. This means that every time we delete a property a new object will be created. This is a performance concern.

Ignore a Data Member with Attributes C#

Now that we understand how to ignore a data attribute with JavaScript, let’s take a look at how that can be done using C# by first looking at our model definition.


/// <summary>
/// device telemetry readings
/// </summary>
public class Telemetry
{
    /// <summary>
    /// device id
    /// </summary>
    [DataMember]
    public int deviceId;

    /// <summary>
    /// internal id
    /// </summary>        
    [IgnoreDataMember]
    public long Id;

    /// <summary>
    /// temperature reading
    /// </summary>
    [DataMember]
    public float Temperature;

    /// <summary>
    /// humidity reading
    /// </summary>
    [DataMember]
    public float Humidity;

    /// <summary>
    /// noise/sound reading
    /// </summary>
    [DataMember]
    public float Sound;     
}

We define our telemetry class with the same attributes as our JSON model. There is however an internal Id data member which we may use for internal purposes, but we do not want to serialize as JSON to the client application. When we want to ignore a property on C#, we can use the IgnoreDataMember attribute which is in the Serialization namespace and declaratively ignore the property.

This IgnoreDataMember  attribute enables us to change the default behavior of the DataContractSerializer which by default serializes all public properties. In our case, we still want to maintain the Id property with public accessibility, so it is available to other backend integrations that are not in the same assembly.

We should note that by setting the Id property to internal or private also prevents the serialization of the property to JSON. This however impacts accessibility to the data member. We need to look at our system requirements and determine the best approach as those other access modifiers prevent the accessibility of that property to other assemblies and classes.

Conclusion

With this article, we are able to see how to omit additional properties in the application model, so we can maintain our JSON contract using both JavaScript for the client app and C# for the backend API. We looked at how depending on the implementation approach we can optimize the solution for time complexity and accessibility concerns.


Thanks for reading.

Originally published by ozkary.com

0 comments :

Post a Comment