3
votes

I am having trouble working out how to handle a response error with retrofit and RxAndroid. onError() gets called if there is a network error or the like but I need to be able to get the response to check if there was an authentication error. Instead what I get is a token with a null String and I can't find out why. What is the best way to go about this?

This is my RxAndroid call at the moment.

    Client.getInstance().getService()
            .getToken(usernameET.getText().toString(), passwordET.getText().toString())
            .subscribe(new Subscriber<SiteInfo>() {
                @Override
                public void onCompleted() {

                }

                @Override
                public void onError(Throwable e) {
                    e.printStackTrace();
                }

                @Override
                public void onNext(SiteInfo siteInfo) {
                    Log.d(TAG, "onNext "+ token.toString());
                }
            });

This is my retrofit service

@GET("my_url_here")
Observable<Token> getToken(
        @Query("username") String username,
        @Query("password") String password
);

This is my Current restadapter

RestAdapter restAdapter = new RestAdapter.Builder()
            .setLogLevel(RestAdapter.LogLevel.FULL)
            .setEndpoint(BASE_URL)
            .build();

service = restAdapter.create(MyService.class);

And this is my Token Class.

public class Token {
    private String token;

    public String getToken() {
        return token;
    }

    public void setToken(String token) {
        this.token = token;
    }

    @Override
    public String toString() {
        return token;
    }
}

How should I go about handlng this. Can it be done in the RxAndroid part or do I need to add something to my RestClient or maybe something else entirely?

Thanks.

Edit

07-01 06:38:04.562    1680-1793/uk.co.dyolo.thing D/Retrofit﹕ ---> HTTP GET my_website_here
07-01 06:38:04.562    1680-1793/uk.co.dyolo.thing D/Retrofit﹕ ---> END HTTP (no body)
07-01 06:38:04.610    1680-1793/uk.co.dyolo.thing D/Retrofit﹕ <--- HTTP 200 my_website_here (48ms)
07-01 06:38:04.610    1680-1793/uk.co.dyolo.thing D/Retrofit﹕ : HTTP/1.1 200 OK
2
What is authentication error? Retrofit's observable emits error if there was status other than 200.eleven
Unfortunately the server doesn't give a status code. {"error":"The username was not found in the database","stacktrace":null,"debuginfo":null,"reproductionlink":null} is the response I get.Radther
The server gives you status. Status codes is a part of http.eleven
Ahh yeah, I get what you mean. The server must be giving me a 200 code then, which isn't very helpful.Radther
I think he is implying that the server sends him 200. But the response contains the error string. In that case, you really can't blame retrofit for this. Ask the module owner to send the error code in response like 500 etc or handle it yourself by parsing the JSON and checking whether error!=null.Ramandeep Nanda

2 Answers

3
votes

I have found a solution

Firstly I expanded my Token object to have an error property.

public class Token {

    private String token;
    private String error;

    public String getToken() {
        return token;
    }

    public void setToken(String token) {
        this.token = token;
    }

    public String getError() {
        return error;
    }

    public void setError(String error) {
        this.error = error;
    }

    @Override
    public String toString() {
        return token;
    }
}

Then I added an operator to my RxJava chain which can check to see if the error field is not null. And if there is an error, throw a custom exception which calls the subscribers onError allowing me to handle it.

if (token.getError() != null) {
    throw OnErrorThrowable.from(new UserAuthenticationException(token.getError()));
    }

And if there is an error, throw a custom exception which calls the subscribers onError allowing me to handle it.

if (e instanceof OnErrorThrowable){
    if (e.getCause() instanceof UserAuthenticationException){
        Log.d(TAG, "onError "+e.getCause().getMessage());
    }
    e.getCause().printStackTrace();
}
1
votes

This is a bit late but if anyone wanders here, Retrofit 2 passes in instance of HttpException into the onError callback whenever the request returned from the server with an error code outside the [200,300) interval ...

throwable -> {
    if(throwable instanceof HttpException){
        switch(((HttpException)throwable).code()){
            // your error handling logic 
        }
    }
}

You can also retrieve the whole reponse from this object..