aneurinc
aneurinc

Reputation: 1238

Retrofit 2: Handling dynamic JSON response

I am using retrofit 2 as a REST client and I cannot figure out how to deserialise a dynamic JSON response.

Depending on the status value (success or failure), our JSON can have two different objects in the result field:

  1. A successful response returns a User object:

    {
       "status": 200,
       "message": "OK",
       "result": {
          "id": "1",
          "email": "[email protected]"
           ...
       }
    }
    
  2. A failed response returns an Error object:

    {
       "status": 100,
       "message": "FAILED",
       "result": {
          "error": "a user with this account email address already exists"
       }
    }
    

I have created 3 POJO classes...

  1. APIResponse:

    public class APIResponse<T> {
        @Expose private int status;
        @Expose private String message;
        @Expose private T result;
        ...
    }
    
  2. User:

    public class User {
        @Expose private String id;
        @Expose private String email;
        ...
    }
    
  3. Error:

    public class Error {
        @Expose private String error;
        ...
    }
    

Here is how I make the call:

@FormUrlEncoded
@PUT(LOGIN)
Call<APIResponse<User>> login(@Field("email") String email, @Field("password") String password);

And here is how I get a response:

@Override
public void onResponse(Call<APIResponse<User>> call, Response<APIResponse<User>> response) {
   ...
}

@Override
public void onFailure(Call<APIResponse<User>> call, Throwable t) {
   ...
}

Question:

The API call expects a return type of Call<APIReponse<User>>. However, it might not get a User object back... So how do I modify this approach to accept either APIResponse<User> or APIResponse<Error>.

In other words, how do I deserialise JSON data that can be in two different formats?

Solutions I have looked at:

  1. Including 'error' field in User class or extending Error class (ugly).
  2. Custom interceptor or converter (struggled to understand).
  3. Convince API devs to change it and make my life easier :)

Upvotes: 1

Views: 2252

Answers (2)

Amad Yus
Amad Yus

Reputation: 2866

I am not sure if the solution is viable, but you can try changing <APIResponse<User>> to <APIResponse<Object>>

Call<APIResponse<Object>> login(@Field("email") String email, @Field("password") String password);

@Override
   public void onResponse(Call<APIResponse<Object>> call, Response<APIResponse<Object>> response) {
   //depending on the response status, you can cast the object to appropriate class
   Error e = (Error)response.body().getResult();
   //or
   User u = (User)response.body().getResult();
}

or another alternative, use String instead of POJO

Call<String> login(@Field("email") String email, @Field("password") String password);

retrieve the JSON and serialize manually or use GSON

Upvotes: 1

n4h1n
n4h1n

Reputation: 357

You should check the response code and use the desired class to process the json

Upvotes: 0

Related Questions