I'm trying to consume a vendor's api using c# and System.Text.Json. Some API calls allow for flags in the request that add sections to the response. I'm not sure how to handle these (lack of experience).
I can send and receive no problem to standard classes if the format doesn't change. How do I design classes to handle these possible sections?
Following are the classes for a SearchItemsRequest
. It contains a SearchItemsRequestSpec
that bundles up the search terms. The SearchItemsRequestSpec.ItemType
governs the base format of the data returned. The SearchItemsRequest.Flags
governs the sections that will be included of that format.
/// <summary>
/// Constructor. Sets up for a new search that will return all items.
/// </summary>
public SearchItemsRequest()
{
Spec = new SearchItemsRequestSpec();
Force = SearchItemsForce.NewSearch;
Flags = 1; // basic response
From = 0; // for new search use 0
To = 0; // return all elements beginning from index specified in the “from” parameter
}
/// <summary>
/// Search Specification
/// </summary>
[JsonPropertyName("spec")]
public SearchItemsRequestSpec Spec { get; set; }
/// <summary>
/// 0 - if such search has been done, then return cached result, 1 - to do a new search
/// </summary>
[JsonPropertyName("force")]
public SearchItemsForce Force { get; set; }
/// <summary>
/// Data flags for the response
/// <para>
/// The value of this parameter depends on item type; data formats of all item types and their flags are described in the chapter <see href="https://sdk.wialon.com/wiki/en/sidebar/remoteapi/apiref/format/format">Data format</see>
/// </para>
/// </summary>
[JsonPropertyName("flags")]
public long Flags { get; set; }
/// <summary>
/// index of the first returned item (for new search use 0)
/// </summary>
[JsonPropertyName("from")]
public uint From { get; set; }
/// <summary>
/// index of the last returned item (if 0 - return all elements beginning from index specified in the “from” parameter)
/// </summary>
[JsonPropertyName("to")]
public uint To { get; set; }
}
/// <summary>
/// Search Criteria
/// <para>
/// <see cref="https://sdk.wialon.com/wiki/en/sidebar/remoteapi/apiref/core/search_items">Search Items API Ref</see>
/// </para>
/// <para>
/// Multi-criteria search is possible<br/>
/// {"itemsType":"avl_unit","propName":"sys_name,rel_user_creator_name","propValueMask":"Volvo*,chdi_test","sortType":"sys_name","propType":"sys_name,rel_user_creator_name","or_logic":0}
/// </para>
/// </summary>
public class SearchItemsRequestSpec
{
/// <summary>
/// Constructor. Defaults are to search for units by unique id
/// </summary>
public SearchItemsRequestSpec()
{
ItemsType = SearchItemsItemType.avl_unit;
PropName = SearchItemsPropName.sys_unique_id;
PropValueMask = string.Empty;
SortType = SearchItemsPropName.sys_unique_id;
PropType = SearchItemsPropType.property;
OrLogic = SearchItemsOrLogic.Disabled;
}
[JsonPropertyName("itemsType")]
public SearchItemsItemType ItemsType { get; set; }
[JsonPropertyName("propName")]
public SearchItemsPropName PropName { get; set; }
[JsonPropertyName("propValueMask")]
public string PropValueMask { get; set; }
/// <summary>
/// Uses the same enum as PropName. Not a typo
/// </summary>
[JsonPropertyName("sortType")]
public SearchItemsPropName SortType { get; set; }
[JsonPropertyName("propType")]
public SearchItemsPropType PropType { get; set; }
[JsonPropertyName("or_logic")]
public SearchItemsOrLogic OrLogic { get; set; }
}
When executing the method, I'm currently hardcoded to only support one item type in the response
internal class SearchItemsResponse
{
[JsonPropertyName("searchSpec")]
public SearchItemsResponseSpec SearchSpec { get; set; }
[JsonPropertyName("dataFlags")]
public uint DataFlags { get; set; }
[JsonPropertyName("totalItemsCount")]
public uint TotalItemsCount { get; set; }
[JsonPropertyName("indexFrom")]
public uint IndexFrom { get; set; }
[JsonPropertyName("indexTo")]
public uint IndexTo { get; set; }
[JsonPropertyName("items")]
public List<Item_UnitBasic> Items { get; set; } //basic data for unit only
}
the possible sections for a unit are
[Flags]
internal enum UnitResponseFlags : long
{
BaseFlag = 1, // 0x00000001
CustomProperties = 2, // 0x00000002
BillingProperties = 4, // 0x00000004
CustomFields = 8, // 0x00000008
Image = 16, // 0x00000010
Messages = 32, // 0x00000020
GUID = 64, // 0x00000040
AdministrativeFields = 128, // 0x00000080
AdvancedProperties = 256, // 0x00000100
AvailableForCurrentMomentCommands = 512, // 0x00000200
LastMessageAndPosition = 1024, // 0x00000400
Sensors = 4096, // 0x00001000
Counters = 8192, // 0x00002000
Maintenance = 32768, // 0x00008000
UnitConfigurationInReports = 131072, // 0x00020000 - trip detector and fuel consumption
ListAllPossibleCommandsForCurrentUnit = 524288, // 0x00080000
MessageParameters = 1048576, // 0x00100000
UnitConnectionStatus = 2097152, // 0x00200000
Position = 4194304, // 0x00400000
ProfileFields = 8388608, // 0x00800000
SetAllPossibleFlags = 4611686018427387903 // 0x3FFFFFFFFFFFFFFF
}
There's a few, and the other item types have their own collections of sections.
If this was basic c#, I'd create an interface and pass that around, but with the deserialization and the possible missing sections, I definitely have a knowledge gap. How do I write a class to handle all the possible permutations of returned data for an item?