0

I have been beating my head against the wall trying to figure out how to parse the data I need from this json response I receive from an api call. Here is the beginning of the response:

{
    "response": {
        "results": [
            [
                1002,
                "Brent's Test Product o Fun",
                "TEST001",
                "1234567-",
                "100000000281",
                "12345678",
                "",
                "",
                true,
                "Brightpearl",
                "2020-06-18T13:38:01.000-05:00",
                "2021-04-27T07:45:24.000-05:00",
                439,
                null,
                74,
                1,
                "LIVE",
                null
            ],
            [
                1003,
                "Brent's Test Product 2",
                "TEST002",
                "",
                "",
                "",
                "",
                "",
                true,
                "Brightpearl",
                "2020-08-31T00:53:26.000-05:00",
                "2021-04-27T07:45:24.000-05:00",
                439,
                null,
                74,
                1,
                "LIVE",
                null
            ],
            [
                1004,
                "Brent's Test Product 3",
                "TEST003",
                "",
                "",
                "",
                "",
                "",
                true,
                "Brightpearl",
                "2020-09-16T00:30:55.000-05:00",
                "2021-04-27T07:45:24.000-05:00",
                439,
                null,
                74,
                1,
                "LIVE",
                null
            ],

What I need to be able to do is loop through the nodes that are nested in "results". These are actually product skus that I need to work with. There is a bunch of metadata returned at the end of the response that I haven't included here.

I have created this class to handle the results.

public class SkuSearchResults
    {
        public int productId { get; set; }
        public string productName { get; set; }
        public string SKU { get; set; }
        public string barcode { get; set; }
        public string EAN { get; set; }
        public string UPC { get; set; }
        public string ISBN { get; set; }
        public string MPN { get; set; }
        public bool stockTracked { get; set; }
        public string salesChannelName { get; set; }
        public string createdOn { get; set; }
        public string updatedOn { get; set; }
        public int brightpearlCategoryCode { get; set; }
        public int productGroupId { get; set; }
        public int brandId { get; set; }
        public int productTypeId { get; set; }
        public string productStatus { get; set; }
        public int primarySupplierId { get; set; }

    }
  • 2
    The array items look to have a fixed schema. Given that is the case **if you were to use Json.NET** you could use the converter from [How to deserialize an array of values with a fixed schema to a strongly typed data class?](https://stackoverflow.com/q/39461518/3744182) to deserialize to a fixed type. And to make restsharp use Json.NET see [Can I set a custom JsonSerializer to RestSharp RestClient](https://stackoverflow.com/q/43849892/3744182) and [RestSharp serialization to JSON, object is not using SerializeAs attribute as expected](https://stackoverflow.com/a/28431284/3744182). – dbc Apr 29 '21 at 15:29
  • Do those questions answer yours sufficiently? – dbc Apr 29 '21 at 15:33
  • @dbc I do have this class defined to handle the contents: I'll add it above. – Brent Allison Apr 29 '21 at 15:41
  • Maybe a "dynamic object" could help here. See: https://stackoverflow.com/questions/3142495/deserialize-json-into-c-sharp-dynamic-object – MartinM43 Apr 29 '21 at 15:42
  • Part of the problem might be that the object contained in the result array are not objects but arrays themselves. Each element in these inner arrays also have no property names, which makes it even more challenging. The Newtonsoft Json library mentioned by @dbc will be helpful, but ultimately you need to resolve the inner array elements to each property of your SkuSearchResults object. BTW, the naming convention would make that singular. Maybe something like `new SkuSearchResults{ productId = array[0], productName = array[1] ...}` – Carlo Bos May 02 '21 at 01:50

1 Answers1

0

If you haven't solved this already, Brightpearl's search endpoints return a generic schema definition and raw results instead of the strongly typed results that the GET endpoints return. Without delving into the reasoning why, you are left with the task of parsing the metadata and the raw results and synthesizing your c# class from that. Luckily (as usual) Newtonsoft will save the day for you.

Create a Response class that will receive the search results

public class GenericSearchResult
{
    /// <summary>
    /// This holds all of the information about the fields returned in the results.
    /// </summary>
    [JsonProperty("metaData")]
    public SearchMetaData MetaData { get; set; }

    /// <summary>
    /// This is the raw data of the search request
    /// </summary>
    [JsonProperty("results")]
    public dynamic[] Results;
}

You can use Postman or similar to get all of the properties that will come back in MetaData, but the important one is the "columns" element, which is an array of the fields returned and the order in which they will appear in the results array.

JsonConvert.Deserialize() your json result into this construct, and you are ready for the manual conversion.

Something along these lines should get you started

List<SkuSearchResults> results = new List<SkuSearchResults>();
foreach (dynamic row in searchResponse.Response.Results)
{
    //First, Create a JObject
    JObject obj = new JObject();
    int idx = 0;

    //Add the properties to the JObject
    foreach (MetaColumn column in searchResponse.Response.MetaData.Columns) 
    {
        obj.Add(new JProperty(column.Name, row[idx++]));
    }

    //Convert it to the target type
    results.Add(obj.ToObject<SkuSearchResults>());
}

If you are doing lots of searches across varying endpoints and result classes, you can of course convert this to a Generic funtion (T) and synthesize anything.

   List<T> MakeObjectsFromSearch<T>(GenericSearchResponse searchResponse)

Don't forget to add some null handling, since those searches frequently return nulls for int fields (like your primarySupplierId and productGroupId properties)

Hope that helps. Definitely made my head hurt for a while as well.

SteveD
  • 36
  • 4