Search code examples
dynamicretrofit2pojo

Retrofit 2: How to handle dynamic response


I am trying fetch data from this api: http://www.omdbapi.com/ I am using Retrofit 2 and created a pojo for first json. The thing I am curious about is how to convert my pojo to second one when data is not available.

When there is data available, It returns this json:

http://www.omdbapi.com/?t=Suits

{
Title: "Suits",
Year: "2011–",
Rated: "TV-14",
Released: "23 Jun 2011",
Runtime: "44 min",
Genre: "Comedy, Drama",
Director: "N/A",
Writer: "Aaron Korsh",
Actors: "Gabriel Macht, Patrick J. Adams, Rick Hoffman, Meghan Markle",
Plot: "On the run from a drug deal gone bad, Mike Ross, a brilliant college-dropout, finds himself a job working with Harvey Specter, one of New York City's best lawyers.",
Language: "English",
Country: "USA",
Awards: "7 nominations.",
Poster: "http://ia.media-imdb.com/images/M/MV5BMTk1MjYzOTU2Nl5BMl5BanBnXkFtZTgwMzAxMTg5MTE@._V1_SX300.jpg",
Metascore: "N/A",
imdbRating: "8.7",
imdbVotes: "244,979",
imdbID: "tt1632701",
Type: "series",
totalSeasons: "6",
Response: "True"
}

When there is no data avilable, it returns this json:

http://www.omdbapi.com/?t=asdasdas

{
Response: "False",
Error: "Movie not found!"
}

Solution

  • You have a couple of options. Out of my head the simplest one is to include the Error field in the original pojo and always check for the field Response. When this is "True" than all the other fields will be present. When "False", only the Error field will be there.

    Another option and perhaps the least flexible and understandable is to have a pojo Error from where you can inherit. You'd still have to inspect the value of Response to check if there's an error. I personally would avoid this option here, but I thought it's good to know you can still do it. Something like this:

    class Error {
      @SerializedName("Error")
      @Expose
      private String error;
      // ...
    }
    
    class Movie extends Error {
      // other fields here
    }
    

    As you can see this is pretty ugly, but works...

    A third option you can try is to check the Http status code. This one depends on the API. If the api returns Http code 200 even when there's an error, then this is not that straight forward. However it's my favourite since it provides more correctness in my opinion.

    Say the api return Http 404 when there's no data. You can then check this status and use a different pojo to deserialise the error body (The pojo could simply be the error message). If you're using retrofit with the built in Callbacks you'd have to do this on onResponse. If you're using RxJava, then this is even more straight forward as you can do it easily in the onError method (All non-2XX http responses land in the onError method).

    You can access the error body of a retrofit response with errorBody. You can convert it to a pojo using Gson or simply using this snippet:

    Converter<ResponseBody, MyError> converter = new GsonConverterFactory()
       .responseBodyConverter(MyError.class, Annotation[0]);
    MyError error = converter.convert(response.errorBody());
    

    (Here MyError would be the name of the pojo containing the error fields).

    You might want to create the converter factory only once. Most probably should be the one you used when creating the Retrofit instance.

    If you're actually using RxJava you can check my answer here on how to access the error body in an Rx response