Search code examples
c#asp.netasp.net-mvcgraphqljson.net

How to deserialize GraphQL response for n no of edges and node in C#


I am trying to deserialize the GraphQL query result which may contain n no of edges and nodes into a class name "Company" but I am getting an error saying:

"Newtonsoft.Json.JsonSerializationException: 'Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.IEnumerable1[ConsoleApp2.Edge1[ConsoleApp2.Location]]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.".

How can I deserialize it into Company Class?

public class Company
    {
        [JsonProperty("name")]
        public string Name { get; set; }

        [JsonProperty("id")]
        public string Id { get; set; }

        [JsonProperty("externalId")]
        public string ExternalId { get; set; }

        [JsonProperty("locations")]
        public IEnumerable<Edge<Location>> Locations { get; set; }
    }

    public class Edge<T>
    {
        [JsonProperty("edges")]
        public IEnumerable<Nodes<T>> Edges { get; set; }
    }

    public class Nodes<T>
    {
        [JsonProperty("node")]
        public T Node { get; set; }
    }

    public class Location
    {
        [JsonProperty("id")]
        public string Id { get; set; }
    }
    public class Program
    {
        static void Main(string[] args)
        {
            var json = "{\"name\":\"ABC Company\",\"id\":\"gid://shopify/Company/12345\",\"externalId\":\"12345\",\"locations\":{\"edges\":[{\"node\":{\"id\":\"gid://shopify/CompanyLocation/12345\"}}]}}";
            var defaultJObject = JsonConvert.DeserializeObject(json);

            // I am getting exception here
            var company = JsonConvert.DeserializeObject<Company>(json);
        }
    }

Solution

  • You have a bug, you need a root class ( class Data below)

    this works for me

        var json = "{\"company\":{\"name\":\"Test\",\"id\":\"gid://shopify/Company/1234\",\"externalId\":\"123451\",\"locations\":{\"edges\":[{\"node\":{\"id\":\"gid://shopify/CompanyLocation/1234\"}}]}},\"userErrors\":[]}";
        Data data = JsonConvert.DeserializeObject<Data>(json);
    
    public partial class Data 
    {
        [JsonProperty("company")]
        public Company Company { get; set; }
    
        [JsonProperty("userErrors")]
        public List<object> UserErrors { get; set; }
    }
    
    public partial class Company
    {
        [JsonProperty("name")]
        public string Name { get; set; }
    
        [JsonProperty("id")]
        public string Id { get; set; }
    
        [JsonProperty("externalId")]
        public long ExternalId { get; set; }
    
        [JsonProperty("locations")]
        public Locations<Node> Locations { get; set; }
    }
    
    public partial class Locations<T>
    {
        [JsonProperty("edges")]
        public List<Edge<T>> Edges { get; set; }
    }
    
    public partial class Edge<T>
    {
        [JsonProperty("node")]
        public T Node { get; set; }
    }
    
    public partial class Node
    {
        [JsonProperty("id")]
        public string Id { get; set; }
    }
    

    IMHO this is more flexible

        Data<Node> data = JsonConvert.DeserializeObject<Data<Node>>(json);
    
    public partial class Data<T> where T:class, new ()
    {
        [JsonProperty("company")]
        public Company<T> Company { get; set; }
    
        [JsonProperty("userErrors")]
        public List<object> UserErrors { get; set; }
    }
    
    public partial class Company<T> 
    {
        [JsonProperty("name")]
        public string Name { get; set; }
    
        [JsonProperty("id")]
        public string Id { get; set; }
    
        [JsonProperty("externalId")]
        public long ExternalId { get; set; }
    
        [JsonProperty("locations")]
        public Locations<T> Locations { get; set; }
    }