Search code examples
c#jsonjson.netstandards

Is it correct to include data as a key name in JSON?


I am consuming an API that is providing a JSON payload. One of the properities in the JSON is actually a data element, thus I'm unable to de-serialize the payload without adding additional classes.

Here is the JSON:

{
      "company": "ABC Inc.",
      "packages": {
          "$package1": {
          "code": "$package1",
          "name": "Foo",
          "price": 1000
        },
        "$package2": {
          "code": "$package2",
          "name": "Bar",
          "price": 2000
        },
        "$package3": {
          "code": "$package3",
          "name": "Another",
          "price": 3000
        }
    }
}

I am able to serialize using Newtonsoft.Json with the following classes:

public class Rootobject
{
    public string company { get; set; }
    public Packages packages { get; set; }
}

public class Packages
{
    public Package1 package1 { get; set; }
    public Package2 package2 { get; set; }
    public Package3 package3 { get; set; }
}

public class Package1
{
    public string code { get; set; }
    public string name { get; set; }
    public int price { get; set; }
}

public class Package2
{
    public string code { get; set; }
    public string name { get; set; }
    public int price { get; set; }
}

public class Package3
{
    public string code { get; set; }
    public string name { get; set; }
    public int price { get; set; }
} 

Using this approach I can de-serialize using Newtonsoft.Json, but if "package4" is added later, then it requires me to make a code change.

Should I push back on the developer of this API and insist on an array of packages, rather than how it is currently implemented?


Solution

  • You can do this using a Dictionary<>, for example:

    public partial class Rootobject
    {
        public string Company { get; set; }
        public Dictionary<string, Package> Packages { get; set; }
    }
    
    public partial class Package
    {
        public string Code { get; set; }
        public string Name { get; set; }
        public long Price { get; set; }
    }
    

    And deserialise like this:

    var result = JsonConvert.DeserializeObject<Rootobject>(json);
    

    And use it like this:

    foreach (var element in result.Packages)
    {
        Console.WriteLine($"Package: {element.Key} has name {element.Value.Name}");
    }
    

    Which would output:

    Package: $package1 has name Foo
    Package: $package2 has name Bar
    Package: $package3 has name Another