iMSn20
iMSn20

Reputation: 255

Deserialize JSON with same answer property name but differents properties inside

I'm implementing an external API who give me a response like this if is OK:

{
    status: "success",
    answer: {
        token: "tokenGenerated..."
    }
}

Or like this if I get an error:

{
    status: "ERROR",
    answer: {
        errorCode: "error code"
        errorMessage: "error message"
    }
}

I'm trying to deserialize the response in two differents class, one for the OK response, and another for the ERROR response. I'm doing something like this:

public class Response
{
    [JsonProperty("status")]
    private string Status { get; set; }
    public bool IsSuccess => Status != "ERROR";
    
    [JsonProperty("answer")]
    public object Response { get; set; }
}

public class ResponseError : Response
{
    [JsonProperty("errorCode")]
    public string ErrorCode { get; set; }

    [JsonProperty("errorMessage")]
    public string ErrorMessage { get; set; }
}

public class ResponseOk : Response
{
    [JsonProperty("token")]
    public string Token { get; set; }
}

And when I get the response I do this:

var readResponse = await response.Content.ReadAsStringAsync();                    
var deserializedResponse = JsonConvert.DeserializeObject<Response>(readResponse);
if (deserializedResponse.IsSuccess)
    return JsonConvert.DeserializeObject<ResponseOk>(readResponse);
else
    return JsonConvert.DeserializeObject<ResponseError>(readResponse);

In my method I return a object. My problem is, for example, if I get an OK status, the property Status is well implemented, and in the Response property I get the "token: "tokenhere"", not in the Token property.

And if I try to put inside the Resposne class the Token property and the errors properties, I need to apply the JsonProperty("answer") in both cases and of course I get an exception.

There's a better way of implementing this for my case? Thx.

Upvotes: 1

Views: 1417

Answers (2)

Jonathan
Jonathan

Reputation: 7541

You can define your classes like this (haven't tested):

public class Response
{
    [JsonProperty("status")]
    private string Status { get; set; }
    public bool IsSuccess => Status != "ERROR";
}

public class ResponseError : Response
{
    [JsonProperty("answer")]
    public ResponseErrorContent answer { get; set; }
}

public class ResponseErrorContent
{
    [JsonProperty("errorCode")]
    public string ErrorCode { get; set; }

    [JsonProperty("errorMessage")]
    public string ErrorMessage { get; set; }
}

public class ResponseOk : Response
{
    [JsonProperty("answer")]
    public ResponseOkContent answer { get; set; }
}

public class ResponseOkContent
{
    [JsonProperty("token")]
    public string Token { get; set; }
}

Upvotes: 0

Roman
Roman

Reputation: 12171

You map answer object in JSON to Response property in Response class.

Having this class:

public class ResponseOk : Response
{
    [JsonProperty("token")]
    public string Token { get; set; }
}

you expect a token property in JSON as root property, but you have token inside answer so this mapping won't work.

You will have the same issue when you get an error - ErrorCode and ErrorMessage also won't be set because you map them to root propeties.

You can change your classes to:

public class Response
{
    [JsonProperty("status")]
    private string Status { get; set; }
    public bool IsSuccess => Status != "ERROR";
    
    [JsonProperty("answer")]
    public Answer Response { get; set; } // can be just renamed to "Answer"
}

public class Answer
{
    [JsonProperty("errorCode")]
    public string ErrorCode { get; set; }

    [JsonProperty("errorMessage")]
    public string ErrorMessage { get; set; }

    [JsonProperty("token")]
    public string Token { get; set; }
}

And now you can check the IsSuccess in Response class and decide what to use - Token or error properties.

Upvotes: 1

Related Questions