Retrofit 2 + RxAndroid: Handle Errors (4xx and some 200)
Asked Answered
B

0

4

I saw a lot of articles and questions about error handling using retrofit combined with RxAndroid, but i am not able to set my configuration right.

What do I want to accomplish:

  1. when receiving a 4xx code: handle it on onError()
  2. when receiving a 2xx code:

    -> try to parse to expected response and deliver it onNext()

    -> If not possible try to convert the JSON answer to MyAPIError class (simple POJO with errorNum and message) and deliver it on onError.

So either 2xx or 4xx http codes might end up in onError().

What do I have at the moment:

ServiceGenerator.java

public class ServiceGenerator {

    private static final HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor()
            .setLevel(HttpLoggingInterceptor.Level.BODY);


    private static final Gson gson = new GsonBuilder()
            .registerTypeAdapter(DateTime.class, (JsonDeserializer<DateTime>) (json, typeOfT, context) -> new DateTime(json.getAsJsonPrimitive().getAsLong())).create();


    public static Retrofit buildRetrofit() {
        return new Retrofit.Builder()
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create(gson))
                .baseUrl("....myURL...")
                .client(getOkHttpClient()).build();
    }

    private static OkHttpClient getOkHttpClient() {
        return new OkHttpClient.Builder()
                .addInterceptor(interceptor)
                .addInterceptor(chain -> {
                    Request request = chain.request().newBuilder()
                               .addHeader(ProductionSettings.HEADER_KEY_TOKEN, "myToken here")
                                .build();
                    return chain.proceed(request);
                })
                .followRedirects(true)
                .followSslRedirects(true)
                .build();
    }


    public static <S> S createService(final Class<S> serviceClass) {
        return buildRetrofit().create(serviceClass);
    }
}

NetworkComunnication.java

public class NetworkCommunication implements UserAPI {
    private static NetworkCommunication instance;
    private final UserAPI userAPI;

    private NetworkCommunication() {
        this.userAPI = ServiceGenerator.createService(UserAPI.class);
    }

    public static NetworkCommunication getInstance() {
        if (instance == null) {
            instance = new NetworkCommunication();
        }
        return instance;
    }

    @Override
    public Observable<UserResponse> updateUser(@Path(UsersSchema.ObjectId) String objectId, @Body final Map<String, Object> body) {
        return userAPI.updateUser(objectId, body);
    }
}

UserIteractor.java

public class UserIteractor {
    private final UserMapper mapper;

    public UserIteractor() {
        this.mapper = new UserMapper();
    }

    public Observable<Boolean> updateUser(Long userObjectID, UserViewModel model) {
        Map<String, Object> reqBody = mapper.mapToUpdateRequestBody(model);
        return NetworkCommunication
                .getInstance()
                .updateUser(userObjectID, reqBody)
                .map(prodUserResponse -> true);
    }

}

I would like to handle everything before it gets to UserInteractor class, so it would be generic for all Interactors and I wouldn't have to make the same logic for all requests. How can I achieve this to be as generic as possible and as "top" as possible?

Bostwick answered 27/3, 2017 at 12:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.