2

I want to consume the Tumblr API in C#. Every request to the API returns a JSON-encoded object with the same general outline:

{
    "meta": {
        "status": 200,
        "msg": "OK"
    },
    "response": { ... }
}

meta is always the same but response is specific to each request. I would like to have all my methods return the C# equivalent of this object:

public class TumblrEnvelope
{
    [JsonProperty("meta")]
    public Meta Meta { get; set; }

    [JsonProperty("response")]
    ???
}

public class Meta
{
    [JsonProperty("status")]
    public int Status { get; set; }

    [JsonProperty("msg")]
    public string Message { get; set; }
}

but I'm not sure if it's possible to implement the Response property in such a way that I can directly serialize every response to a TumblrLEnvelope.

return JsonConvert.DeserializeObject<TumblrEnvelope>(result);

Can this be done? If not, what would be the closest I could get to it?

  • You're getting a JSON response, why not just keep the results as a JSON response? If you don't, you're just going to have to rebuild dictionaries, lists & all the other stuff inside your magic response object with no real benefit. – Sean McSomething Jan 26 '17 at 0:33
  • @SeanMcSomething Because that's honestly just kind of annoying to do, requires a lot more typing and thinking about what exactly is inside of the object you're working with at any time. Also because I'm building a website on top of a Content Management System that I plan to store content from Tumblr in and it will be a lot easier to have one common model for both content retrieved from the database and from API requests. – Lawyerson Jan 26 '17 at 8:13
5

If you are using Json.Net at least. You can mix and match Jobjects with static types as you see fit. In you case it is simply a matter of doing.

public class TumblrEnvelope
{
    [JsonProperty("meta")]
    public Meta Meta { get; set; }

    [JsonProperty("response")]
    public JObject Response { get; set; }
}

Then you can taste the response and you want to turn it into a static type you can simply do(as suggested in comments by Caleth)

switch (e.Meta.Status) 
{ 
    case 200: return e.Response.ToObject<Tumblr200Response>(); 
    case 404: return e.Response.ToObject<Tumblr404Response>();
    ...
}
  • I guess creating models for each response is my best bet. That being said, if I'm creating a separate object for every response anyway, I think I'm better off making them all inherit TumblrEnvelope and implement their own Response property. That way I won't have to taste the response and serialize it in two steps; and in case of a bad request where Meta contains and error, Response will just be null, if I'm not mistaken. – Lawyerson Jan 26 '17 at 11:54
  • @BauceLawyerson you still have to do two step deserialization, as when you recieve the response you don't know which ResponseType to create – Caleth Jan 26 '17 at 13:00
  • The example should show that there will be disparate types for different statuses, e.g. switch (e.Meta.Status) { case 200: return e.Response.ToObject<Tumblr200Response>(); case 404: return e.Response.ToObject<Tumblr404Response>(); ... } – Caleth Jan 26 '17 at 13:04
  • @Caleth I thought Json.NET automatically handled this by simply only mapping properties that can be mapped to the provided object and ignore the rest. Whenever meta.status is something other then 200, the API returns "response": [], which I assumed would just become null if it can't be mapped to whatever ResponseType I try to deserialize it to. – Lawyerson Jan 26 '17 at 13:32
  • That only works if response is blank in all but 1 status. 206 partial content etc could be a consideration – Caleth Jan 26 '17 at 13:34
0

You don't know the form of the response part in advance: for instance, in a case of an HTTP 403, response part will be very different from what you get with HTTP 200.

Therefore, you can't simply deserialize the response using a given class. What you can do, of course, is to set the Response property to be dynamic, but this won't benefit you much.

What you can do, however, is to have a two-step deserialization:

  1. You start by deserializing the JSON response to an object which expects only two fields: /meta/status and /meta/msg. Once you have this meta information, the method can process it to check against the common errors, and handle them respectively (either by throwing an exception or by performing any appropriate task such as requesting credentials to the user.)

  2. Once you know that you have a response with the status 200 and message “OK,” you do the second deserialization, this time to a complete object containing the expected fields.

Or you can do it in the opposite direction:

  1. Attempt to deserialize to a fully qualified object that you expect to receive when everything went fine.

  2. If it fails, deserialize just to an object which expects the two meta fields, and handle the situation accordingly.

This way, you'll slightly optimize the performance if most of your responses are successful, since you'll deserialize those responses only once.

  • So I should basically just create a different model for every request that inherits from TumblrEnvelope and has its own Response property? I actually don't think I'd need to serialize in two steps, because if I got an error status code back, the response would just be null. – Lawyerson Jan 25 '17 at 23:01
0

You could actually deserialize in one step, as the first thing you'd do with the HTTP response is to check its status code - and you don't need to parse any JSON to do that. Once you know whether you've get the expected response or an error code, you can parse the JSON into the correct class.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.