Home > other >  How to structure my models to match my JSON?
How to structure my models to match my JSON?

Time:04-25

I'm just new to API and I wanted to consume third party API that was provided to me(which I don't have any control on how they structure the datas). I have asked on S.O before this post but I can't understand what or how should I do their suggestions 'Structure your classes to match your JSON Object'

My Json looks like this :

{
    "status": 1,
    "message": "",
    "data": {
        "VacationLeave": 11,
        "SickLeave": 10,
        "EmergencyLeave": 2,
        "HolidaySwap": 1,
        "OldLeave": 1
    }
}

And on my controllers I have this

public IActionResult APICall() 
{
    // Fetch the JSON string from URL.
    List<APIResponse> leaves = new List<APIResponse>();
    string apiUrl = "http://xxxxx.xxx.xxx/GetLeaveBalance/2170";

    HttpClient client = new HttpClient();
    HttpResponseMessage response = client.GetAsync(apiUrl).Result;

    if (response.IsSuccessStatusCode)
    {
        leaves = JsonConvert.DeserializeObject<List<APIResponse>>(response.Content.ReadAsStringAsync().Result);
    }

    // Return the Deserialized JSON object.
    return Json(leaves);
}

My model classes :

public class APIResponse : LeaveModel
{
    public int Status { get; set; }
    public string Message { get; set; }

    public List<LeaveModel> Leaves;
}

public class LeaveModel
{
    public int VacationLeave { get; set; }
    public int SickLeave { get; set; }
    public int EmergencyLeave { get; set; }
    public int HolidaySwap { get; set; }
    public int OldSwap { get; set; }
}

My problem is: I get this error :

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

Can anyone help me what I'm missing here?

Thank you

CodePudding user response:

As per json ApiResponse class must look like this

 public class APIResponse : LeaveModel
{
    public int Status { get; set; }
    public string Message { get; set; }

    public LeaveModel data;
}

CodePudding user response:

Your APIResponse should support generic.

public class APIResponse<T>
{
    public int Status { get; set; }
    public string Message { get; set; }

    public T Data { get; set; }
}

As the data is a LeaveModel object but not a LeaveModel array.

And deserialize as APIResponse<LeaveModel> type.

APIResponse<LeaveModel> apiResponse = JsonConvert.DeserializeObject<APIResponse<LeaveModel>>(response.Content.ReadAsStringAsync().Result);
LeaveModel leave = apiResponse.Data;

And would suggest changing the method to asynchronous.

public async Task<IActionResult> APICallAsync() 
{
    //Fetch the JSON string from URL.
    LeaveModel leave = new LeaveModel();
    string apiUrl = "http://xxxxx.xxx.xxx/GetLeaveBalance/2170";

    HttpClient client = new HttpClient();
    HttpResponseMessage response = await client.GetAsync(apiUrl);
    if (response.IsSuccessStatusCode)
    {
        APIResponse<LeaveModel> apiResponse = JsonConvert.DeserializeObject<APIResponse<LeaveModel>>(await response.Content.ReadAsStringAsync());  
        leave = apiResponse.Data;        
    }

    //Return the Deserialized JSON object.
    return Json(leave);
}
  • Related