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 (integer, optional),
temperature (number, optional),
humidity (number, optional),
sound (number, optional)
}
|
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.
0 comments :
Post a Comment
What do you think?