codecutout / JsonApiSerializer

JsonApiSerializer supports configurationless serializing and deserializing objects into the json:api format (http://jsonapi.org).
MIT License
113 stars 46 forks source link

Jsonapi data attributes not accessible. #111

Open hakunagndoro opened 5 years ago

hakunagndoro commented 5 years ago

I am not able to retrieve the attributes in the jsonapi response data object using the JsonApiSerializer. I am able to retrieve only the Id and and the type properties. I am using the DocumentRoot class. My model looks like this:

    public class Commodity
    {
        [JsonProperty(propertyName: "Id")]
        public string CommodityId { get; set; }

        [JsonProperty(propertyName: "type")]
        public string Type { get; set; } = "node--commodity";

        [JsonProperty(propertyName: "Description")]
        public string Description { get; set; }

        [JsonProperty(propertyName:"GradeOverride")]
        public bool GradeOverride { get; set; }

        [JsonProperty(propertyName :"UnitOfMeasure")]
        public string UnitOfMeasure { get; set; }

        [JsonProperty(propertyName: "KgPerUnit")]
        public int KgPerUnit { get; set; }

        [JsonProperty(propertyName: "IsDeleted")]
        public bool IsDeleted { get; set; }

        [JsonProperty(propertyName: "ProductCode")]
        public string ProductCode { get; set; }

        [JsonProperty(propertyName: "Weighted")]
        public bool Weighted { get; set; }

    }

This is how I am trying to retrieve the attributes:

 class Program
    {
        static void Main(string[] args)
        {  

              var client = new RestClient("http://localhost/gp/api/node/commodity");
              var request = new RestRequest();
              request.AddHeader("Content-Type", "application/vnd.api+json");
              request.AddHeader("Authorization", "Basic YXBpOmFwaQ == ");
              request.AddHeader("Accept", "application/vnd.api+json");
              request.Method = Method.GET;
              IRestResponse res = client.Execute(request);

              var response = JsonConvert.SerializeObject(JsonConvert.DeserializeObject(res.Content), Formatting.Indented);            

              DocumentRoot<Commodity[]> commodities = 
                JsonConvert.DeserializeObject<DocumentRoot<Commodity[]>>(response, new JsonApiSerializerSettings());

              Console.WriteLine(response);
              Console.WriteLine();
              Console.WriteLine("I am expecting my code to give me the values as on the above json. But this is what I am getting.");
              Console.WriteLine();

            foreach (var item in commodities.Data)
            {
                Console.WriteLine($"Id ::::: {item.CommodityId}");
                Console.WriteLine($"GradeOverride::::: {item.GradeOverride}");
                Console.WriteLine($"UnitOfMeasure::::: {item.UnitOfMeasure}");
                Console.WriteLine($"Weighted::::: {item.Weighted}");
                Console.WriteLine($"Description::::: {item.Description}");
                Console.WriteLine($"KgPerUnit::::: {item.KgPerUnit.ToString()}");
                Console.WriteLine($"ProductCode::::: {item.ProductCode}");
                Console.WriteLine($"isDeleted::::: {item.IsDeleted}");
                Console.WriteLine($"Type::::: {item.Type}");

            }

            Console.ReadLine();
        }
    }

As you can see from my json response, and the attributes not being set with the correct values from the response. Where am I going wrong?

Response

{
    "jsonapi": {
        "version": "1.0",
        "meta": {
            "links": {
                "self": {
                    "href": "http://jsonapi.org/format/1.0/"
                }
            }
        }
    },
    "data": [
        {
            "type": "node--commodity",
            "id": "0de115ee-1c41-40cf-8df5-12eac9947a59",
            "attributes": {
                "Description": "RunnerBeans",
                "GradeOverride": true,
                "IsDeleted": false,
                "KgPerUnit": "1",
                "ProductCode": "MCA",
                "UnitOfMeasure": "Kg",
                "Weighted": false
            },
            "links": {
                "self": {
                    "href": "http://localhost/gp/api/node/commodity/0de115ee-1c41-40cf-8df5-12eac9947a59?resourceVersion=id%3A3"
                }
            }
        }
    ],
    "links": {
        "self": {
            "href": "http://localhost/gp/api/node/commodity"
        }
    }
}

The incorrect output, only showing the Id and Type set correctly.

Id ::::: 0de115ee-1c41-40cf-8df5-12eac9947a59
GradeOverride::::: False
UnitOfMeasure:::::
Weighted::::: False
Description:::::
KgPerUnit::::: 0
ProductCode:::::
isDeleted::::: False
Type::::: node--commodity
alex-davies commented 5 years ago

It looks like it is not identifying the Commodity as a ResourceObject.

The default check to determine if its a resource object looks specifically for an Id property not taking into consideration the [JsonProperty]. As commodity does not have an Id property (only a CommodityId field) it is doing regular json deserialization on it

This is not the expected behaviour and I believe this is a legitimate bug and will attempt to get a fix for this issue

In the meantime you could rename CommodityId to Id. Or alternatively extend ResourceObjectConverter and override CanConvert to add custom logic to identify the attribute, this extended converter can be passed to the JsonApiSerializerSettings constructor

hakunagndoro commented 5 years ago

I can confirm renaming CommodityId to Id resolved my issue.

Thank you @alex-davies.