I usually receive a json response from an API
{
"errors": "Error message"
}
My issue is that the same api can return me some other response with another format :
{
"errors": [
{ "message": "error message 1", "description": "error description 1" },
{ "message": "error message 2", "description": "error description 2" }
]
}
My issue is that i have to deserialize this response and map it to an object in order to return it with some formatting.
namespace namespace.models
{
public class ErrorResponse
{
[JsonProperty(PropertyName = "errors")]
public ErrorDetail[] Errors { get; set; }
}
}
I use the following code to handle a post request :
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Authorization", "Bearer " token);
HttpContent content = new StringContent(
JsonConvert.SerializeObject(request),
Encoding.UTF8,
"application/json");
HttpResponseMessage httpResponse = await client.PostAsync(url, content);
string output = await httpResponse.Content.ReadAsStringAsync();
PostResponse returnValue = new PostResponse ();
if (httpResponse.StatusCode == (HttpStatusCode)201)
{
returnValue.Id = Int32.Parse(output);
}
else
{
ErrorResponse response = JsonConvert.DeserializeObject<ErrorResponse>(output)
throw new Exception(httpResponse.ReasonPhrase " " output);
}
return returnValue;
}
My issue is that idon't know how to handle a response that can be a string and then my exception should be the "output" i received, or an array of object. Should i return this as string too ? Or is there a way to handle the reponse differently ?
CodePudding user response:
Unfortunately, there is no way to easily Deserialize here using JsonConvert.DeserializeObject. It could be done with the custom converter but for me, it is too much hassle.
Luckily you could easily parse the response into JObject, then check the type of JToken and convert them to the required type like so
var json1 = "{\r\n \"errors\": \"Error message\"\r\n}";
var json2 = "{\r\n \"errors\": [\r\n { \"message\": \"error message 1\", \"description\": \"error description 1\" },\r\n { \"message\": \"error message 2\", \"description\": \"error description 2\" }\r\n ]\r\n}";
var jo = JObject.Parse(json2);
var errResponse = new ErrorResponse();
if (jo["errors"] is JArray array)
{
errResponse.Errors = array.ToObject<ErrorDetail[]>() ?? Array.Empty<ErrorDetail>();
}
else
{
errResponse.Errors = new[] { new ErrorDetail() { Message = jo["errors"]?.Value<string>() ?? string.Empty } };
}
CodePudding user response:
I created two classes and use try catch. One is having a member errors declared as string and the second has an array of object.
public static void Main(string[] args)
{
var json1 = "{\r\n \"errors\": \"Error message\"\r\n}";
var json2 = "{\r\n \"errors\": [\r\n { \"message\": \"error message 1\", \"description\": \"error description 1\" },\r\n { \"message\": \"error message 2\", \"description\": \"error description 2\" }\r\n ]\r\n}";
try
{
ErrorsResponse response =
JsonConvert.DeserializeObject<ErrorsResponse>(json1);
Console.WriteLine(response.ToString());
}
catch (Exception e)
{
ErrorResponse response =
JsonConvert.DeserializeObject<ErrorResponse>(json1);
Console.WriteLine(response.ToString());
}
}
I didn't try the other solution. I'm going to test them.
CodePudding user response:
try this
string output = await httpResponse.Content.ReadAsStringAsync();
if (httpResponse.StatusCode == (HttpStatusCode)201)
{
returnValue.Id = Int32.Parse(output);
}
else
{
var jsonObject = JObject.Parse(output);
var errorResponse = jsonObject["errors"].GetType().Name == "JArray" ?
jsonObject2.ToObject<ErrorResponse>() :
new ErrorResponse { Errors = new ErrorDetail[]
{ new ErrorDetail { Message = (string)jsonObject["errors"], Description="Short error format" } } };
throw new Exception(httpResponse.ReasonPhrase " "
string.Join("; \r\n", errorResponse.Errors.Select(i=> "Message: " i.Message
" Description: " i.Description)); );
}
return returnValue;
or you can use this code as well
classes
public class ErrorResponse
{
[JsonProperty("errors")]
public ErrorDetail[] Errors { get; set; }
}
public partial class ErrorDetail
{
[JsonProperty("message")]
public string Message { get; set; }
[JsonProperty("description")]
public string Description { get; set; }
}
