0

Our back-end implements a Login API with responses like this:

Successful Response:

{
    "response": "SUCCESS",
    "details": {
        "user_id": "912341",
        "name": "John Doe",
        "email": "johndoe@gmail.com",
        "address": "John Doe's House",
        "birthdate": "2018-07-09",
        "profile_file_id": null
    }
}

Error reponse:

{
    "response": "FAILED",
    "details": "Invalid email"
}

How can I make my GSON and Retrofit Serializer dynamic to allow data changes like this? I am using Retrofit 2, Gson, and RxJava2CallAdapterFactory.

Dale Julian
  • 1,560
  • 18
  • 35
  • may be its not possible with help of GSON, either you have to add different key string like "error":"error message" and check if it is null or empty? – Nirav Bhavsar Jul 10 '18 at 10:02
  • you want to both data fetching. –  Jul 10 '18 at 10:03
  • Possible duplicate of [How to handle Dynamic JSON in Retrofit?](https://stackoverflow.com/questions/24279245/how-to-handle-dynamic-json-in-retrofit) – Navneet Krishna Jul 11 '18 at 03:10

3 Answers3

1

make pojo class like this way..

public class Details{

@SerializedName("address")
private String address;

@SerializedName("birthdate")
private String birthdate;

@SerializedName("profile_file_id")
private Object profileFileId;

@SerializedName("user_id")
private String userId;

@SerializedName("name")
private String name;

@SerializedName("email")
private String email;

public void setAddress(String address){
    this.address = address;
}

public String getAddress(){
    return address;
}

public void setBirthdate(String birthdate){
    this.birthdate = birthdate;
}

public String getBirthdate(){
    return birthdate;
}

public void setProfileFileId(Object profileFileId){
    this.profileFileId = profileFileId;
}

public Object getProfileFileId(){
    return profileFileId;
}

public void setUserId(String userId){
    this.userId = userId;
}

public String getUserId(){
    return userId;
}

public void setName(String name){
    this.name = name;
}

public String getName(){
    return name;
}

public void setEmail(String email){
    this.email = email;
}

public String getEmail(){
    return email;
}

}

ResponseData..

public class ResponseData extends ErrorResponse{

@SerializedName("response")
private String response;

@SerializedName("details")
private String details;

public void setResponse(String response){
    this.response = response;
}

public String getResponse(){
    return response;
}

public void setDetails(String details){
    this.details = details;
}

public String getDetails(){
    return details;
}

}

Error Response..

public class ErrorResponse {

@SerializedName("response")
private String response;

@SerializedName("details")
private String details;

}

make api call into interface..

@GET("path")
Call<ResponseData> getUserData();

api called.

        Call<ResponseData> dataCall=apiInterface.getUserData();
    dataCall.enqueue(new Callback<ResponseData>() {
        @Override
        public void onResponse(Call<ResponseData> call, Response<ResponseData> response) {
            if (response!=null && response.isSuccessful() && response.body()!=null){

            }
            else{
                if (response.errorBody()!=null){
                    ErrorResponse errorResponse=new Gson().fromJson(response.errorBody().toString(),ErrorResponse.class);
                    Log.d("Error data",response.errorBody().toString());
                }
            }
        }

        @Override
        public void onFailure(Call<ResponseData> call, Throwable t) {

        }
    });
1
public class ResponseData {

    @SerializedName("response")
    private String response;

    @SerializedName("details")
    private String details;

    public String getError(){
        if(response.equals("FAILED")
            return details;
        else return null; 
    }

    public UserData getUserData(){
        if(response.equals("SUCCESS")
           return new Gson().fromJson(details, UserData.class);
        else return null;
    }

and Retrofit2 with RxJava2

MaybeObserver<ResponseData> getUserData(...)

However in my opinion your API design introduces some failure potential. Use HTTP response codes instead.

Viktor Stojanov
  • 708
  • 6
  • 20
  • This is true. I'll suggest to change it to a more semantic way next time. However, I changed your `String details` to a `JsonElement`. But this worked! Thanks! – Dale Julian Jul 11 '18 at 08:29
0

Is not correct to use the same property to contain 2 semantically different types of information. You are sort of applying polymorphism on a class internally (using the state of some inner porperty to decide the content type of some other porperty). What I would do is add another property parallel do details, like errorDetails which will be populated with the error reason in the case where an error occurs. In this case you have 2 separate fields to handle the data according to the type of response.

NiVeR
  • 9,644
  • 4
  • 30
  • 35